在 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;
}


原文链接地址:http://blog.exsvc.cn/article/csharp-async-deadlock.html
转载请注明:转载自 易科博客 ,谢谢!

发表评论

电子邮件地址不会被公开。 必填项已用*标注