CSh*_*ark 6 .net c# synchronizationcontext task-parallel-library async-await
我在使用HttpClient发送http请求时遇到间歇性死锁,有时它们永远不会返回到await SendAsync我的代码中.我能够找出处理内部请求的线程HttpClient/ HttpClientHandler由于某种原因SynchronizationContext它在死锁期间有一个.我想弄清楚如何使用线程最终得到a SynchronizationContext,通常他们没有.我会假设无论什么对象导致SynchronizationContext设置它也会阻塞Thread,这会导致死锁.
我是否能够在TPL ETW事件中看到任何相关内容?
我该如何解决这个问题?
编辑2:
我注意到这些死锁的地方是在ServiceContractwindows服务中的wcf (参见下面的代码)中.该SynchronizationContext所导致的问题实际上是一个是WindowsFormsSynchronizationContext,我以为是一些控制入门创建并造成没有清理正确(或者类似).我意识到几乎可以肯定不应该在Windows服务中发生任何Windows窗体的事情,我并不是说我同意它是如何使用的.但是,我没有使用它编写任何代码,我不能轻易地改变所有的引用.
编辑:这是我遇到问题的wcf服务的一般概念的一个例子.这是一个简化版本,而不是确切的代码:
[ServiceContract]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
internal class SampleWcfService
{
private readonly HttpMessageInvoker _invoker;
public SampleWcfService(HttpMessageInvoker invoker)
{
_invoker = invoker;
}
[WebGet(UriTemplate = "*")]
[OperationContract(AsyncPattern = true)]
public async Task<Message> GetAsync()
{
var context = WebOperationContext.Current;
using (var request = CreateNewRequestFromContext(context))
{
var response = await _invoker.SendAsync(request, CancellationToken.None).ConfigureAwait(false);
var stream = response.Content != null ? await response.Content.ReadAsStreamAsync().ConfigureAwait(false) : null;
return StreamMessageHelper.CreateMessage(MessageVersion.None, "GETRESPONSE", stream ?? new MemoryStream());
}
}
}
Run Code Online (Sandbox Code Playgroud)
添加ConfigureAwait(false)到上面的2个地方并没有完全解决我的问题,因为用于服务进入此处的wcf请求的线程池线程可能已经有了SynchronizationContext.在这种情况下,请求会一直通过整个GetAsync方法并返回.然而,它仍然最终陷入僵局System.ServiceModel.Dispatcher.TaskMethodInvoker,因为在那个微软代码中,它没有使用ConfigureAwait(false),我想假设有一个很好的理由(供参考):
var returnValueTask = returnValue as Task;
if (returnValueTask != null)
{
// Only return once the task has completed
await returnValueTask;
}
Run Code Online (Sandbox Code Playgroud)
感觉真的错了,但是将它转换为使用APM(开始/结束)而不是使用任务修复此问题?或者,唯一的解决方法是只更正未SynchronizationContext正确清理的代码?
尝试下面;我在类似的情况下成功进入了异步兔子洞。
var responsebytes = await response.Content.ReadAsByteArrayAsync();
MemoryStream stream = new MemoryStream(filebytes);
Run Code Online (Sandbox Code Playgroud)
响应流变量。
希望能帮助到你。
| 归档时间: |
|
| 查看次数: |
518 次 |
| 最近记录: |