介绍
async/await中使用阻塞式代码会导致死锁
下面这段代码会导致死锁,程序卡死
private void btnTest_Click(object sender, EventArgs e)
{
var htmlTask = GetHtmlAsync(new Uri("https://www.taobao.com"));
MessageBox.Show(htmlTask.Result);
}
public static async Task<string> GetHtmlAsync(Uri uri)
{
using (var client = new HttpClient())
{
var html = await client.GetStringAsync(uri);
return html;
}
}
防止死锁
- 在你的异步方法中,返回未完成Task时都调用ConfigureAwait(false)。
- 始终使用 Async,不要混合阻塞式代码和异步代码(推荐)。因为当你在异步代码中阻塞程序,将失去异步代码带来的所有好处。
ConfigureAwait:
ConfigureAwait(continueOnCapturedContext: false):continueOnCapturedContext参数表示是否尝试将延续任务封送回原始上下文。
ConfigureAwait(false)改变了GetJsonAsync的延续行为,使它不用在原来的context中恢复。GetJsonAsync将直接在线程池线程中恢复,这使得GetJsonAsync能完成任务,并且无需重新进入原来的context
private void btnTest_Click(object sender, EventArgs e)
{
var htmlTask = GetHtmlAsync(new Uri("https://www.taobao.com"));
MessageBox.Show(htmlTask.Result);
}
public static async Task<string> GetHtmlAsync(Uri uri)
{
using (var client = new HttpClient())
{
var html = await client.GetStringAsync(uri).ConfigureAwait(false);
return html;
}
}
在ASP.NET Core框架中,已经移除SynchronizationContext。所以像上面案例中的用法不会出现死锁,但是你不能保证你的异步方法不被winform、wpf、asp.net使用