异步/等待的例子,导致死锁 [英] An async/await example that causes a deadlock

查看:191
本文介绍了异步/等待的例子,导致死锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用C#的异步遇到了一些最佳实践来抓异步编程/等待关键字(我是新的C#5.0)。

一给出的建议之一是以下内容:

稳定性:了解你的同步上下文

...
某些同步上下文是不可重入和单线程的。这意味着只有一个工作的单位所用的上下文中在给定的时间被执行。这样的一个例子是Windows UI线程或ASP.NET请求上下文。
在这些单线程同步环境中,很容易死锁自己。如果从单线程上下文催生了一个任务,然后等待在上下文的任务,你的等待code可能会阻止后台任务。

 公众的ActionResult ActionAsync()
{
    //死锁:在异步任务此块
    VAR数据= GetDataAsync()结果。    返回查看(数据);
}私人异步任务<串GT; GetDataAsync()
{
    //一个非常简单的异步方法
    VAR的结果=等待MyWebService.GetDataAsync();
    返回result.ToString();
}

如果我试图剖析它自己,主线程派生到一个新的MyWebService.GetDataAsync();,但由于主线程等待在那里,等待的结果GetDataAsync()的结果。 。同时,说数据已准备就绪。为什么不主线程继续它的执行逻辑和GetDataAsync()?

返回一个字符串结果

有人可以解释我为什么在上面的例子中死锁?
我完全无能的问题是什么...


解决方案

参加的这里,斯蒂芬有明确的答案给你:


  

因此​​,这是什么情况,首先是最高级的方法
  (为的button1_Click UI / MyController.Get为ASP.NET):


  
  

      
  1. 中的顶级方法调用GetJsonAsync(用户界面/ ASP.NET范围内)。


  2.   
  3. GetJsonAsync通过调用HttpClient.GetStringAsync(仍在范围内)开始REST请求。


  4.   
  5. GetStringAsync返回未完成任务,说明REST请求是不完整的。


  6.   
  7. GetJsonAsync等待由GetStringAsync返回的任务。上下文被捕获,并将被用来继续运行
      GetJsonAsync方法以后。 GetJsonAsync返回未完成的任务,
      指示GetJsonAsync方法是不完整的。


  8.   
  9. 中的顶级方法对任务同步块返回的GetJsonAsync。此块的背景主题。


  10.   
  11. ......最终,REST请求将完成。这样就完成了一个由GetStringAsync返回的任务。


  12.   
  13. 有关GetJsonAsync延续现在已经准备好运行,它等待的情况下可用,因此它可以在上下文中执行的。


  14.   
  15. 死锁。顶层方法阻塞线程的上下文,等待GetJsonAsync完成,GetJsonAsync正在等待
      上下文是免费的,所以它能够完成。为UI例如,
      背景是UI方面;为ASP.NET例如,背景是
      ASP.NET请求上下文。这种类型的死锁可以引起
      无论是背景。


  16.   

另一个链接,你应该阅读:

在等待着,UI,和死锁!噢,我的!

I came across some best practices for asynchronous programming using c#'s async/await keywords (I'm new to c# 5.0).

One of the advices given was the following:

Stability: Know your synchronization contexts

... Some synchronization contexts are non-reentrant and single-threaded. This means only one unit of work can be executed in the context at a given time. An example of this is the Windows UI thread or the ASP.NET request context. In these single-threaded synchronization contexts, it’s easy to deadlock yourself. If you spawn off a task from a single-threaded context, then wait for that task in the context, your waiting code may be blocking the background task.

public ActionResult ActionAsync()
{
    // DEADLOCK: this blocks on the async task
    var data = GetDataAsync().Result;

    return View(data);
}

private async Task<string> GetDataAsync()
{
    // a very simple async method
    var result = await MyWebService.GetDataAsync();
    return result.ToString();
}

If I try to dissect it myself, the main thread spawns to a new one in "MyWebService.GetDataAsync();", but since the main thread awaits there, it waits on the result in "GetDataAsync().Result". Meanwhile, say the data is ready. Why doesn't the main thread continue it's continuation logic and returns a string result from GetDataAsync() ?

Can someone please explain me why there is a deadlock in the above example? I'm completely clueless about what the problem is ...

解决方案

Take a look example in here, Stephen has clear answer for you:

So this is what happens, starting with the top-level method (Button1_Click for UI / MyController.Get for ASP.NET):

  1. The top-level method calls GetJsonAsync (within the UI/ASP.NET context).

  2. GetJsonAsync starts the REST request by calling HttpClient.GetStringAsync (still within the context).

  3. GetStringAsync returns an uncompleted Task, indicating the REST request is not complete.

  4. GetJsonAsync awaits the Task returned by GetStringAsync. The context is captured and will be used to continue running the GetJsonAsync method later. GetJsonAsync returns an uncompleted Task, indicating that the GetJsonAsync method is not complete.

  5. The top-level method synchronously blocks on the Task returned by GetJsonAsync. This blocks the context thread.

  6. ... Eventually, the REST request will complete. This completes the Task that was returned by GetStringAsync.

  7. The continuation for GetJsonAsync is now ready to run, and it waits for the context to be available so it can execute in the context.

  8. Deadlock. The top-level method is blocking the context thread, waiting for GetJsonAsync to complete, and GetJsonAsync is waiting for the context to be free so it can complete. For the UI example, the "context" is the UI context; for the ASP.NET example, the "context" is the ASP.NET request context. This type of deadlock can be caused for either "context".

Another link you should read:

Await, and UI, and deadlocks! Oh my!

这篇关于异步/等待的例子,导致死锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆