我正在尝试这个异步代码只是为了测试 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
并且什么都不做(return关键字永远不会被执行)..
如果我在两个“异步方法”之前设置等待并删除Task.WaitAll
它有效..那么我做错了什么?
因为您的方法看起来像 ASP.NET MVC 控制器操作,所以我假设您正在 ASP.NET 上运行。
默认情况下,异步方法会在其暂停的同一上下文中恢复(即您调用的位置)await
)。在 ASP.NET 中,这意味着当前请求上下文。并且一次只能有一个线程处于特定上下文中。所以,发生的事情是执行的线程Index()
位于请求上下文中,阻塞于WaitAll()
。另一方面,两个调用AsyncMethod()
正在尝试在相同的上下文中恢复(在完成下载后),但他们无法这样做,因为Index()
仍在该上下文中执行。因此,这些方法位于deadlock http://en.wikipedia.org/wiki/Deadlock所以什么也没有发生。
(同样的死锁也会发生在 GUI 应用程序中,因为 GUI 上下文在这方面的行为类似。控制台应用程序不存在此问题,因为它们没有任何上下文。)
解决此问题的方法有两个:
-
永远不要同步等待async
方法。 (可能唯一的例外是如果想从Main()
控制台应用程序的方法。)
相反,异步等待它们。在你的情况下,这意味着使用await Task.WhenAll(a, b)
.
-
Use ConfigureAwait(false)
在您的“库”方法中(即那些实际上不需要在请求上下文上执行的方法)。
使用 1 或 2 可以解决您的问题,但最好同时使用两者。
有关此问题的更多信息,请阅读 Stephen Cleary 的文章不要阻止异步代码 http://nitoprograms.blogspot.cz/2012/07/dont-block-on-async-code.html.
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)