我在乔恩·斯凯特(Jon Skeet)的“ C#深入。第三版”中找到了以下示例:
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
说“等一会儿,我会回到你的第二个int类型”。Main
继续执行并偶然发现lengthTask.Result
导致主线程阻塞并等待lengthTask
完成其工作。GetStringAsync
完成并等待主线程变得可用以执行Length
并开始继续。但似乎我误会了一些东西。为什么此代码不会死锁?
关于等待/异步死锁的这个StackOverflow问题中的代码似乎执行相同的操作,但是死锁。
await
返回原始同步上下文,无论是UI线程(在桌面UI应用程序中)还是ASP.NET(不是核心)中的请求上下文。
在GUI应用程序中,您会遇到死锁,因为UI线程被锁定了.Result
。await
将永远等待这个电话结束。
控制台应用程序和ASP.NET Core没有同步上下文,因此调用.Result
不会导致死锁。
VS 15.3的PS:
Visual Studio 2017 15.3预览版2(gasp)允许异步主应用程序。有了它,您可以编写:
public static Task Main()
{
var length = await GetPageLengthAsync("http://csharpindepth.com");
Console.WriteLine(length);
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句