Task.WaitAll 保持循环

2024-04-29

我正在尝试这个异步代码只是为了测试 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 上下文在这方面的行为类似。控制台应用程序不存在此问题,因为它们没有任何上下文。)

解决此问题的方法有两个:

  1. 永远不要同步等待async方法。 (可能唯一的例外是如果想从Main()控制台应用程序的方法。)

    相反,异步等待它们。在你的情况下,这意味着使用await Task.WhenAll(a, b).

  2. Use ConfigureAwait(false)在您的“库”方法中(即那些实际上不需要在请求上下文上执行的方法)。

使用 1 或 2 可以解决您的问题,但最好同时使用两者。

有关此问题的更多信息,请阅读 Stephen Cleary 的文章不要阻止异步代码 http://nitoprograms.blogspot.cz/2012/07/dont-block-on-async-code.html.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Task.WaitAll 保持循环 的相关文章

随机推荐