【问题标题】:Why does this async/await code NOT cause a deadlock?为什么这个 async/await 代码不会导致死锁?
【发布时间】:2017-11-16 13:31:18
【问题描述】:

我在 Jon Skeet 的“C# in depth. 3rd edition”中找到了以下示例:

static async Task<int> GetPageLengthAsync(string url)
{
    using (HttpClient client = new HttpClient())
    {
        Task<string> fetchTextTask = client.GetStringAsync(url);
        int length = (await fetchTextTask).Length;
        return length;
    }
}

public static void Main()
{
    Task<int> lengthTask = GetPageLengthAsync("http://csharpindepth.com");
    Console.WriteLine(lengthTask.Result);
}

我预计这段代码会死锁,但事实并非如此。

在我看来,它是这样工作的:

  1. Main 方法在主线程中同步调用 GetPageLengthAsync
  2. GetPageLengthAsync 发出一个异步请求并立即将Task&lt;int&gt; 返回到Main 说“等一下,我会在一秒钟内返回一个int”。
  3. Main 继续执行并偶然发现 lengthTask.Result 导致主线程阻塞并等待 lengthTask 完成其工作。
  4. GetStringAsync 完成并等待主线程可用以执行 Length 并开始继续。

但我好像误会了什么。为什么这段代码不会死锁?

this StackOverflow question about await/async deadlock 中的代码似乎也是如此,但出现了死锁。

【问题讨论】:

  • 对于死锁,您需要两个异步活动竞争共享资源。我不明白你为什么认为这是这种情况。
  • @Jodrell 这是 GUI/ASP.NET 应用程序中的常见问题 - .Result 会阻塞 UI 线程,因此 await 无法返回到原始同步上下文。对于 ASP.NET 也是如此。控制台和 .NET Core 应用程序,包括 ASP.NET Core 没有同步上下文
  • @juharr OP 提出了一个有效的问题。如果您在 WinForms、WPF 或 ASP.NET 应用程序中尝试此代码,您可能陷入死锁

标签: c# asynchronous async-await task-parallel-library


【解决方案1】:

await 返回原始同步上下文,无论是 UI 线程(在桌面 UI 应用程序中)还是 ASP.NET 中的请求上下文(不是核心)。

在 GUI 应用程序中,您会遇到死锁,因为 UI 线程被 .Result 锁定。 await 将永远等待此调用完成。

控制台应用程序和 ASP.NET Core 没有同步上下文,因此调用 .Result 不会导致死锁。

VS 15.3 的 PS:

Visual Studio 2017 15.3 Preview 2 (gasp) 允许异步主应用程序。有了它,你可以写:

public static Task Main()
{
    var length = await GetPageLengthAsync("http://csharpindepth.com");
    Console.WriteLine(length);
}

【讨论】:

  • 我猜你使用 STA 的任何时候。 RE VS2017 15.3 Preview 2,终于!看起来很有趣。
  • @Jodrell 这与 STA 无关,线程池线程是 MTA 设计的。这是关于在不同平台上实现同步上下文的方式。 ASP.NET Core 只是不使用像 ASP.NET 这样的请求上下文。控制台应用程序开始时不需要同步上下文
  • @Jodrell 查看 Stephen Cleary 的 ASP.NET Core SynchronizationContext 以获得更多建议
猜你喜欢
  • 2020-08-20
  • 2012-08-27
  • 2019-12-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多