我正在尝试此异步代码,仅用于测试async关键字:
public async Task<string> AsyncMethod()
{
var link = "http://www.google.com";
var webclient = new WebClient();
var result = await webclient.DownloadStringTaskAsync(new Uri(link));
return result;
}
public async Task<ActionResult> Index()
{
var a = AsyncMethod();
var b = AsyncMethod();
Task.WaitAll(a, b);
return View();
}
但是当我调试它时,调试器会按
Task.WaitAll
却什么也不做(返回键永远不会执行)。如果我在两个'AsyncMethod'之前设置await并删除
Task.WaitAll
,则它起作用。.那么我在做什么错呢? 最佳答案
因为您的方法看起来像ASP.NET MVC控制器操作,所以我假设您正在ASP.NET上运行。
默认情况下,异步方法在挂起的同一上下文(即您调用await
的上下文)上恢复。在ASP.NET中,这表示当前请求上下文。一次只能在一个特定的上下文中使用一个线程。因此,发生的事情是执行Index()
的线程在请求上下文中,在WaitAll()
中被阻塞。另一方面,AsyncMethod()
的两个调用都试图在相同的上下文上(在完成下载之后)恢复,但是它们不能这样做,因为Index()
仍在该上下文中执行。因此,这些方法位于deadlock中,因此没有任何反应。
(在GUI应用程序中也会发生同样的死锁,因为GUI上下文在这方面的行为类似。控制台应用程序没有此问题,因为它们没有任何上下文。)
解决方法是双重的:
切勿同步等待async
方法。 (唯一的例外可能是如果要从控制台应用程序的Main()
方法执行异步方法。)
而是,异步地等待它们。在您的情况下,这意味着使用await Task.WhenAll(a, b)
。
在您的“库”方法中使用ConfigureAwait(false)
(即那些不需要在请求上下文中强制执行的方法)。
使用1或2可以解决您的问题,但是最好同时执行。
有关此问题的更多信息,请阅读Stephen Cleary的文章Don't Block on Async Code。
关于c# - Task.WaitAll保持循环,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14046471/