在 UI界面或者ASP.NET中调用async的异步代码时如果async和task.Result混用会出现线程被阻塞锁死的情况。
导致阻塞的示例代码:
public static async Task<JObject> GetJsonAsync(Uri uri)
{
// 请勿在实际使用过程中将 httpclient 放在 using 中,此处仅是示例
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
}
public void Button1_Click(...)
{
var jsonTask = GetJsonAsync(...);
textBox1.Text = jsonTask.Result;
}
阻止死锁的两种办法:
使用 ConfigureAwait(false)
public static async Task<JObject> GetJsonAsync(Uri uri)
{
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri).ConfigureAwait(false);
return JObject.Parse(jsonString);
}
}
默认情况下,当您使用async/await时,它将在开始请求的原始线程上继续运行(状态机)。但是,如果当前另一个长时间运行的进程已经接管了该线程,那么你就不得不等待它完成。要避免这个问题,可以使用ConfigureAwait的方法和false参数。当你用这个方法的时候,这将告诉Task它可以在任何可用的线程上恢复自己继续运行,而不是等待最初创建它的线程。这将加快响应速度并避免许多死锁。
但是,当使用此方法后,线程同步上下文将丢失,从而转变成异步操作,如果在之后继续操作界面元素等,会提示线程不安全。
使用 Async 方法进行调用
public async void Button1_Click(...)
{
var json = await GetJsonAsync(...);
textBox1.Text = json;
}
原文链接地址:https://blog.exsvc.cn/article/csharp-async-deadlock.html
- EOF -
技术群:添加小编微信dotnet999
公众号:Dotnet讲堂