我在 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);
}
我预计这段代码会死锁,但事实并非如此。
在我看来,它是这样工作的:
-
Main
方法调用GetPageLengthAsync
在主线程中同步。 -
GetPageLengthAsync
发出异步请求并立即返回Task<int>
至Main
说“等一下,我会在一秒钟内返回给你一个整数”。 -
Main
继续执行并偶然发现lengthTask.Result
这会导致主线程阻塞并等待lengthTask
完成它的工作。 -
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/