使用 HttpClient 进行调试时出现死锁

Deadlock while debugging using HttpClient

提问人:LeBigCat 提问时间:10/17/2023 最后编辑:Heretic MonkeyLeBigCat 更新时间:10/17/2023 访问量:116

问:

我必须使用 HttpClient(发送数百个请求)查询外部 Web 服务。 我使用 HttpClient 制作了一个经典的异步 await 循环,但在调试时,大约 5-10% 的时间 Visual Studio 会冻结,不确定它是否是死锁。取消令牌不起作用,我必须使用任务管理器终止进程。 使用命令提示符启动程序时,我仍然遇到 0 问题。

代码冻结在 上。有时只需 3 到 4 个 HTTP 请求即可。 目标服务是一家著名的酒店供应商(无法共享 ID),我将在最终版本中使用节流器。SendAsyncSemaphoreSlim

使用 .NET 5.0.18 (.NET 4.5) Visual Studio 2019 (16.11)Visual Studio 2019 (16.11)Visual Studio 2019 (16.11)Visual Studio 2019 (16.11)Visual Studio 2019 (16.11)
Visual Studio 2019 (

我阅读了这个 GitHub 问题并禁用了我的问题,但这并没有解决我的问题。System.Runtime.TieredCompilationSystem.Runtime.ProfApi_RejitOnAttachruntimeconfig.template.json

public class WebServiceCaller {
    //wont be release atm
    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>();

        //KO while debuging about 10% of the time after 2=> 6 http SendAsync call
        urls.ForEach(url => {
            taskList.Add(HttpClientToolsSendAsync(url, cts.Token));
        });
        await Task.WhenAll(taskList).ConfigureAwait(false);


        //work when using a thread pool
        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)  {
        //wathever for the moment
        string result = string.Empty;
        try  {
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
            HttpRequestMessage request = new HttpRequestMessage()
            {
                RequestUri = new Uri(url),
                Method = HttpMethod.Get,
            };
            //my ids
            string clearIds = "Login:Password";
            request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Base64Encode(clearIds));

            //deadlock - bug here
            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)  {
            //fire or forget, we dont really want to manage exception
            //wont be catch by tasks.when all
            result = ex.Message;
        }
        return result;
    }

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

主课:

class Program
    {
        private static async Task Main(string[] args)
        {
            //i have a function generating my url here
            List<string> urls = new List<string>();
            WebServiceCaller caller = new WebServiceCaller();
            //configure await added everywhere because this code could be used as a library later
            await caller.CallerAynx(urls).ConfigureAwait(false);
            Console.ReadLine();
        }
    }

visualstudiofreeze

C# visual-studio async-await 死锁 dotnet-httpclient

评论

0赞 Eldar 10/17/2023
不要在线程之间共享。请改用,让每个线程都使用自己的 .HttpClientHttpClientFactoryHttpClient
5赞 Charlieface 10/17/2023
就调用而言,@Eldar线程是安全的。HttpClientSendAsync
1赞 Paulo Morgado 10/17/2023
请注意,.NET 5.0 已停止支持近 18 个月,如果出现问题,则不会修复。它是否适用于 .NET 6.0、.NET 7.0 或 .NET 8.0?
1赞 Panagiotis Kanavos 10/17/2023
@Eldar HttpClient 是完全线程安全的。HttpClientFactory 用于回收套接字,而不是因为线程问题
1赞 Guru Stron 10/17/2023
“使用 .NET 5.0.18 (.NET 4.5)” - 那么您实际使用的是什么? .NET 5 还是 .NET Framework 4.5?

答: 暂无答案