【发布时间】:2015-12-26 10:39:12
【问题描述】:
众所周知,异步方法上的同步等待会导致死锁 (例如,参见Don't Block on Async Code)
我在 Windows 窗体应用程序中单击按钮的事件处理程序中有以下代码(即调用代码时安装了 UI SynchronizationContext)。
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.com"));
Task<HttpResponseMessage> t = client.SendAsync(request);
t.Wait();
var response = t.Result;
我完全预料到代码会在单击按钮时死锁。但是,我实际看到的是同步等待——对话框有一段时间没有响应,然后像往常一样接受事件。
当我尝试同步等待 client 异步方法时,我总是看到死锁。但是,同步等待 library 异步方法(如 SendAsync 或 ReadAsByteArrayAsync)似乎不会死锁。有人可以解释这种行为吗?
.NET 库中异步方法的实现是否在内部使用 await 语句,因此必须将延续编组回原始 SynchronizationContext?
注意: 如果我定义一个客户端方法,说
public async Task<byte[]> wrapperMethod()
{
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.com"));
var response = await client.SendAsync(request);
return await response.Content.ReadAsByteArrayAsync();
}
然后在按钮单击处理程序中说byte[] byteArray = wrapperMethod().Result;,我确实遇到了死锁。
【问题讨论】:
-
正如接受的答案所描述的那样,没有死锁,因为大多数 Microsoft .NET 代码不会在捕获的上下文中恢复。但是,根据这一点要小心。特别是,我相信
HttpClient在某些移动平台上确实使用了await(并且 - 错误地 - 在捕获的上下文中恢复)。
标签: c# asynchronous async-await deadlock synchronizationcontext