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

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

问题描述

我遇到了一些使用 c# 的 async/await 关键字进行异步编程的最佳实践(我是 c# 5.0 的新手).

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

给出的建议之一如下:

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

...一些同步上下文是不可重入的和单线程的.这意味着在给定时间只能在上下文中执行一个工作单元.这方面的一个示例是 Windows UI 线程或 ASP.NET 请求上下文.在这些单线程同步上下文中,很容易让自己陷入死锁.如果您从单线程上下文中生成任务,然后在上下文中等待该任务,您的等待代码可能会阻塞后台任务.

... 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();
}

如果我尝试自己剖析它,主线程会在 MyWebService.GetDataAsync(); 中生成一个新线程,但是由于主线程在那里等待,它在 GetDataAsync().Result.同时,说数据准备好了.为什么主线程不继续它的延续逻辑并从 GetDataAsync() 返回一个字符串结果?

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 ...

推荐答案

查看 这个例子,Stephen 给你一个明确的答案:

Take a look at this example, Stephen has a clear answer for you:

这就是发生的事情,从顶级方法开始(Button1_Click 用于 UI/MyController.Get 用于 ASP.NET):

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

  1. 顶级方法调用 GetJsonAsync(在 UI/ASP.NET 上下文中).

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

GetJsonAsync 通过调用 HttpClient.GetStringAsync(仍在上下文中)启动 REST 请求.

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

GetStringAsync 返回未完成的Task,表示REST请求未完成.

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

GetJsonAsync 等待 GetStringAsync 返回的 Task.上下文被捕获,稍后将用于继续运行 GetJsonAsync 方法.GetJsonAsync返回一个未完成的Task,说明GetJsonAsync方法没有完成.

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.

顶级方法同步阻塞 GetJsonAsync 返回的 Task.这会阻塞上下文线程.

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

... 最终,REST 请求将完成.这完成了 GetStringAsync 返回的 Task.

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

GetJsonAsync 的延续现在可以运行了,它会等待上下文可用,以便在上下文中执行.

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.

死锁.顶层方法正在阻塞上下文线程,等待 GetJsonAsync 完成,而 GetJsonAsync 正在等待上下文空闲以便它可以完成.对于 UI 示例,上下文"是 UI 上下文;对于 ASP.NET 示例,上下文"是 ASP.NET 请求上下文.任何一种上下文"都可能导致这种类型的死锁.

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".

您应该阅读的另一个链接:等待、UI 和死锁!哦,天哪!

Another link you should read: Await, and UI, and deadlocks! Oh my!

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

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