我在可移植类库中创建了一个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;
}
尽管存在于任何类型的压力下,但这显示出一个有趣的问题。它似乎在内部陷入僵局。就像我创建了5个线程并从中发送POST请求一样,这个方法将会到达 nothing 但超时的位置。内容永远不会到达服务器,并且永远不会执行.Continue
代码。但是,如果我连续运行它,或者甚至可以使用2或3个线程运行它可以正常工作。看来,抛出更多线程会使性能呈指数级下降
究竟我在这里做错了什么?
答案 0 :(得分: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所以等待不可用。
答案 1 :(得分:0)
以下代码中包含了一些内容:
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;
}
}
答案 2 :(得分:0)
当同时发出多个请求时,我也观察到了HttpClientHandler问题。 (.NET Framework 4.7.2)
我可以通过将.NET Core 2.1 SocketsHttpHandler反向移植到.NET Framework来解决此问题,并且当同时发出数十个多个请求时,backported implementation的性能得到了显着改善。