You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调试HttpClient异步请求时出现疑似死锁致VS冻结问题求助

调试异步HttpClient请求时Visual Studio冻结,命令行运行正常

问题现象

  • 使用HttpClient调用外部WebService(需发送数百次请求),采用标准async/await循环实现
  • 调试时约5-10%概率出现Visual Studio完全冻结,疑似死锁,取消令牌失效,只能通过任务管理器终止进程;命令行启动程序无任何异常
  • 代码固定卡在SendAsync调用处,有时仅发送3-4次请求就触发问题
  • 目标服务为知名酒店供应商(无法提供认证ID),最终版本计划使用SemaphoreSlim做请求限流

环境信息

  • .NET 5.0.18(兼容.NET 4.5)
  • Visual Studio 2019(版本16.11)

已尝试的无效方案

  • 修改runtimeconfig.template.json,禁用System.Runtime.TieredCompilation和System.Runtime.ProfApi_RejitOnAttach,问题仍存在

相关代码

WebServiceCaller类

public class WebServiceCaller {
    // 当前不会释放
    protected static readonly HttpClient clientSingleton = new HttpClient();

    public async Task<string> CallerAynx(List<string> urls) {
        CancellationTokenSource cts = new CancellationTokenSource();
        cts.CancelAfter(30000);
        Stopwatch watchTime = new Stopwatch();
        watchTime.Start();
        string formattedDateTime = DateTime.Now.ToString("dddd, dd MMMM yyyy HH:mm:ss");
        List<Task> taskList = new List<Task>();

        // 调试时触发问题:约10%概率,发送2-6次请求后卡死
        urls.ForEach(url => {
            taskList.Add(HttpClientToolsSendAsync(url, cts.Token));
        });
        await Task.WhenAll(taskList).ConfigureAwait(false);


        // 使用线程池方式可正常运行
        await Task.Run(() =>  urls.ForEach(url =>  {
            taskList.Add(HttpClientToolsSendAsync(url, cts.Token));
        }));
        await Task.WhenAll(taskList).ConfigureAwait(false);


        watchTime.Stop();
        Console.WriteLine($"Final ASYNC: {watchTime.Elapsed}");
        return "OK";
    }

    private async Task<string> HttpClientToolsSendAsync(string url, CancellationToken cancellationToken)  {
        string result = string.Empty;
        try  {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            HttpRequestMessage request = new HttpRequestMessage()
            {
                RequestUri = new Uri(url),
                Method = HttpMethod.Get,
            };
            // 认证信息
            string clearIds = "Login:Password";
            request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Base64Encode(clearIds));

            // 死锁发生处
            var response = await clientSingleton.SendAsync(request, HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false);
            if (response.IsSuccessStatusCode) {
                result = await response.Content.ReadAsStringAsync(cancellationToken).ConfigureAwait(false);
            }
            else {
                result = "KOHTTP";
            }
        }
        catch (Exception ex)  {
            // 无需处理异常,直接记录消息
            result = ex.Message;
        }
        return result;
    }

    private static string Base64Encode(string textToEncode) {
        byte[] textAsBytes = Encoding.UTF8.GetBytes(textToEncode);
        return Convert.ToBase64String(textAsBytes);
    }
}

Main类

class Program
{
    private static async Task Main(string[] args)
    {
        // 此处有生成URL的逻辑
        List<string> urls = new List<string>();
        WebServiceCaller caller = new WebServiceCaller();
        // 全局添加ConfigureAwait(false),因为代码后续会作为类库使用
        await caller.CallerAynx(urls).ConfigureAwait(false);
        Console.ReadLine();
    }
}

补充截图

Visual Studio冻结状态截图


解决方案建议

  1. 调整调试器设置:

    • 关闭Visual Studio的“启用仅我的代码”选项(工具→选项→调试→常规),避免调试器在异步栈跟踪时出现阻塞
    • 禁用“启用.NET Framework源代码单步执行”,减少调试器对异步代码的干预
  2. 优化HttpClient使用方式:

    • 将ServicePointManager.SecurityProtocol的设置移到类静态构造函数中,避免每次请求重复设置:
      static WebServiceCaller()
      {
          ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
      }
      
    • 避免在循环中直接使用ForEach添加任务,改用LINQ生成任务列表,减少闭包可能带来的问题:
      var taskList = urls.Select(url => HttpClientToolsSendAsync(url, cts.Token)).ToList();
      
  3. 调整异步调试配置:

    • 在Visual Studio中,进入“调试→选项→调试→符号”,取消勾选“Microsoft符号服务器”,减少调试时符号加载的阻塞
    • 尝试升级Visual Studio到最新可用版本(16.11的后续更新包),修复旧版本调试器的异步处理bug
  4. 临时调试替代方案:

    • 如果调试冻结问题持续,可先使用命令行配合dotnet trace工具进行性能分析,定位死锁或阻塞点,避免依赖Visual Studio调试器

内容的提问来源于stack exchange,提问作者LeBigCat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 11:47:32