我看到了一些有关使用 C# 的 async
/await
关键字进行异步编程的最佳实践(我对 C# 5.0 还比较陌生)。
给出了其中一个建议:
稳定性:了解同步上下文
... 一些同步上下文是不可重入和单线程的。这意味着在给定时间内只能在上下文中执行一个工作单元。例如,Windows UI 线程或 ASP.NET 请求上下文都是如此。 在这些单线程同步上下文中,很容易死锁自己。如果你从单线程上下文中生成一个任务,然后在该上下文中等待该任务,那么你的等待代码可能会阻塞后台任务。
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()
返回一个字符串结果呢?请问有人能解释一下为什么上面的例子会出现死锁吗? 我完全不知道问题出在哪里...
var data = GetDataAsync().Result;
也是一行代码,在不应该阻塞的上下文中绝对不应该执行(如UI或ASP.NET请求)。即使它没有死锁,也会阻塞线程不确定的时间。 所以基本上这是一个糟糕的例子。[在执行这样的代码之前,您需要从UI线程中退出,或者像Toni建议的那样也使用await
] - ToolmakerSteve