【发布时间】:2021-09-18 07:35:33
【问题描述】:
我遇到了一些使用 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()返回一个字符串结果?
有人可以解释一下为什么上面的例子会出现死锁吗? 我完全不知道问题是什么......
【问题讨论】:
-
你真的确定 GetDataAsync 完成了它的工作吗?或者它卡住了导致只是锁定而不是死锁?
-
这是提供的示例。据我了解,它应该完成它的工作并准备好某种结果......
-
为什么还要等任务呢?你应该等待,因为你基本上失去了异步模型的所有好处。
-
补充@ToniPetrina 的观点,即使没有死锁问题,
var data = GetDataAsync().Result;是一行代码,应该永远在你不应该的上下文中完成块(UI 或 ASP.NET 请求)。 即使它没有死锁,它也会在不确定的时间内阻塞线程。 所以基本上这是一个糟糕的例子。 [你需要在执行这样的代码之前离开 UI 线程,或者像 Toni 建议的那样在那里使用await。]
标签: c# task-parallel-library deadlock async-await c#-5.0