c# - 为什么这个异步/等待代码不会导致死锁?

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

我在 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<int>Main说“等一下,我会在一秒钟内返回给你一个整数”。
  3. Main继续执行并偶然发现 lengthTask.Result这会导致主线程阻塞并等待 lengthTask完成它的工作。
  4. GetStringAsync完成并等待主线程可用于执行 Length并开始继续。

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

this StackOverflow question about await/async deadlock中的代码似乎也是这样做的,但是死锁了。

最佳答案

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

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

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

VS 15.3 附注:

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

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

关于c# - 为什么这个异步/等待代码不会导致死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44544053/

相关文章:

javascript - 带有多个标记的谷歌地图 javascript => 标签文本在循环中无处不在

javascript - 无法让 Javascript 函数从 gridview 中的文本框触发

C# WinSCP .NET 程序集 : How to upload multiple files asynchronously

c# - 表达混合彩色区域

c# - 如何检查c#代码中死锁的可能性

async-await - 等待,它是如何工作的?

javascript - Node.JS:写入文件时 Promise 产生 null

c# - 在 Main 方法中等待 - 谁获得控制权,直到任务完成?

c# - 在WiX安装中从C#自定义操作调用PowerShell命令

c# - 在 Entity Framework 7 中显式映射接口(interface)成员