还有另一个HttpClient /异步死锁
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了还有另一个HttpClient /异步死锁相关的知识,希望对你有一定的参考价值。
我几个小时以来一直在敲我的头,我已经把手举到这个空中了。据我所知,我遇到了围绕HttpClient和Async的死锁。
目标是让一系列不相关的帖子快速连续发布,等待所有人完成,然后从结果集构建一个文档。该程序有一个WPF UI,这是由按钮触发的:
private async void Generate_Suite_BTN_Click(object sender, RoutedEventArgs e)
{
var suiteBuilder = new SuiteBuilder();
await Task.Run(() => suiteBuilder.worker_Run());
}
这会触发worker_Run(),它有一些切换逻辑,并最终导致命中具有Parrallel.Foreach的SendFiles(),因为发送文件不需要是顺序的,并且彼此无关:
private bool SendFiles()
{
var result = Parallel.ForEach(_InfoCollection, SendFile);
return result.IsCompleted;
}
其中的每一个(并行)都在SendFile()中等待,它也有一些切换逻辑,基于我们发送的内容,但最终归结为:
var result = await Client.SendMessage ( vars );
results.Add(result.MessageId, result.StatusCode, result.HttpReason);
这是SendMessage()中的HttpClient部分:
public async Task<Result> SendMessage(vars)
{
var soapResponse = new XmlDocument();
try
{
Client.DefaultRequestHeaders.Add("SOAPAction", soapAction);
Client.Timeout = TimeSpan.FromSeconds(Timeout);
var content = new StringContent(soapRequest, Encoding.UTF8, contentType);
var post = await Client.PostAsync(url, content).ConfigureAwait(false);
var response = post.Content;
result.StatusCode = post.StatusCode;
result.HttpReason = post.ReasonPhrase;
var sResponse = await response.ReadAsStringAsync().ConfigureAwait(false);
soapResponse.Load(sResponse);
}
catch (Exception ex)
{
//Catch logic
}
}
我可以看到请求和响应与Fiddler来回传递,但是我遇到了逐行调试的麻烦,因为只要我点击PostAsync,VS就会一直翻转并一直持续到程序结束,跳过所有断点。同时,请求超时后会出现TaskCanceledException,很久之后应该完成的代码已经完成。
我在SO和其他地方看了几十个问答,但他们只是没有帮助找到问题。大多数似乎都集中在Async调用上的“.ConfigureAwait(false)”的自由散布上,但它似乎并没有任何影响。
所以,在评论中@JSteward的帮助下,他指出async
和Parrallel.ForEach
不太适合一起工作,因为应该避免在处理异步时返回类型的void
。
他建议我只使用Async,从顶部(按钮点击)到底部(消息发送),然后就可以了。感谢他的指导。
这个链接有助于解释为什么会这样:Async/Await - Best Practices in Asynchronous Programming
SendFiles最终看起来像这样:
private async Task<bool> SendFiles()
{
var result = _InfoCollection.Select(SendFile);
await Task.WhenAll(result).ConfigureAwait(false);
return true;
}
所有其他方法去了async
,有适当的awaits
,返回类型的Task
或Task<T>
。
以上是关于还有另一个HttpClient /异步死锁的主要内容,如果未能解决你的问题,请参考以下文章