为什么HttpClient似乎在这里死锁?

问题描述 投票:1回答:3

我有一个在可移植类库中制作的API,需要联系特定于平台的API才能发送HTTP请求。这是我写的在WinRT上执行HTTP POST的方法:

   public bool Post(IEnumerable<KeyValuePair<string, string>> headers, string data)
    {
        bool success = false;
        HttpClient client = new HttpClient(new HttpClientHandler {AllowAutoRedirect = false});
        foreach (var header in headers)
        {
            client.DefaultRequestHeaders.Add(header.Key, header.Value);
        }

        try
        {
            var task=client.PostAsync(endpoint, new StringContent(data, Encoding.UTF8, "text/xml")).ContinueWith( postTask =>
                    {
                        try
                        {
                            postTask.Wait(client.Timeout); //Don't wait longer than the client timeout.
                            success = postTask.Result.IsSuccessStatusCode;
                        }catch {}
                    }, TaskContinuationOptions.LongRunning);
            task.ConfigureAwait(false);
            task.Wait(client.Timeout);

        }
        catch
        {
            success = false;
        }

        return success;
    }

尽管这在施加[[any压力时会出现一个有趣的问题。它似乎在内部陷入僵局。就像我创建5个线程并从中发送POST请求一样,此方法将到达它将执行nothing但超时的地方。内容永远不会到达服务器,并且永远不会执行.Continue代码。但是,如果我串行运行它,甚至运行2或3个线程,也可以正常运行。似乎抛出的线程更多,但性能却成倍恶化]

我究竟在这里做错了吗?
c# networking windows-runtime dotnet-httpclient winrt-async
3个回答
2
投票
我不认为这是您的问题所在,但可能会出现,并且很容易实现和测试。默认情况下,Windows将“最大网络连接数”设置为2,如果线程数超过2,则可能会锁定连接池。您可以将其添加到您的应用程序配置中

<system.net> <connectionManagement> <add address="*" maxconnection="300" /> </connectionManagement> </system.net>

或通过代码可以执行此操作

ServicePointManager.DefaultConnectionLimit = 300

我还会考虑在继续中注释掉等待。我认为没有必要。

try { //Comment this line out your handling it in the outside task already //postTask.Wait(client.Timeout); //Don't wait longer than the client timeout. success = postTask.Result.IsSuccessStatusCode; }catch {}

最后,如果上述两件事不起作用,我会尝试注释掉这段代码。

//Task.ConfigureAwait(false);

可能是Task.Wait加上设置Task.ConfigureAwait(false)的组合会导致某种死锁,但我对这不是专家。我只知道我有一些运行多线程的非常相似的代码,而且我的代码中没有Task.ConfigureAwait(false),主要是因为我尝试了HttpClient库,但没有升级到.NET 4.5因此无法使用等待。

0
投票
以下是当前代码向我展示的一些内容:

当任务为[[complete时,

    ContinueWith将委托排队以运行。因此,无需等待。
  • LongRunning在这里不需要;这会降低性能,因为您的连续性非常快,根本不需要长时间运行。
  • [ConfigureAwait是没有意义的,因为没有await(并且无论如何都将返回值丢弃)。
  • 不需要将超时传递给Task.Wait,因为无论如何,该任务已经在该超时之后完成了。
  • 我有一个在可移植类库中制成的API,需要联系特定于平台的API才能发送HTTP请求。
    我建议您的API使用HTTP,因此请使其异步。如果要在PCL中完全支持Microsoft.Bcl.Async / async,则可以使用await

    public async Task<bool> Post(IEnumerable<KeyValuePair<string, string>> headers, string data) { HttpClient client = new HttpClient(new HttpClientHandler {AllowAutoRedirect = false}); foreach (var header in headers) { client.DefaultRequestHeaders.Add(header.Key, header.Value); } try { var result = await client.PostAsync(endpoint, new StringContent(data, Encoding.UTF8, "text/xml")).ConfigureAwait(false); return result.IsSuccessStatusCode; } catch { return false; } }


  • 0
    投票
    我能够通过将.NET Core 2.1 SocketsHttpHandler反向移植到.NET Framework来解决此问题,并且当同时发出数十个多个请求时,backported implementation显着提高了性能。
    © www.soinside.com 2019 - 2024. All rights reserved.