为什么不调用Task <t> .Result死锁?

时间:2015-07-06 23:21:55

标签: c# asynchronous async-await deadlock dotnet-httpclient

在几个月前阅读this帖子后,我变得偏执了Result Task<T> ConfigureAwait(false)并且不断地用Task.Run包裹了我的所有电话或public static void Main(string[] args) { var arrays = DownloadMany(); foreach (var array in arrays); } IEnumerable<byte[]> DownloadMany() { string[] links = { "http://google.com", "http://microsoft.com", "http://apple.com" }; using (var client = new HttpClient()) { foreach (var uri in links) { Debug.WriteLine("Still here!"); yield return client.GetByteArrayAsync(uri).Result; // Why doesn't this deadlock? } } } 。但是,由于某种原因,以下代码成功完成:

Still here!

代码打印HttpClient 3次然后退出。具体到Result是否可以安全地致电ConfigureAwait(false)(就像编写它的人用Parcelable填充它一样)?

1 个答案:

答案 0 :(得分:10)

Task.Result只会在某些SynchronizationContext存在的情况下阻止。在控制台应用程序中没有一个,因此在ThreadPool上安排了延续。就像使用ConfigureAwait(false)时一样。

在UI线程中,例如,有一个调度单个UI线程的延续。如果您使用UI线程与Task.Result同步等待,那么只能在UI线程上完成的任务,您就会陷入僵局。

此外,死锁取决于GetByteArrayAsync的实施。如果它是异步方法并且等待不使用ConfigureAwait(false),则只能死锁。

如果您愿意,可以使用Stephen Cleary AsyncContext为您的控制台应用添加适当的SynchronizationContext,以测试您的代码是否可以阻止在UI应用(或ASP.Net)中

关于HttpClient(以及大多数.NET)任务返回方法:它们在技术上并不是异步。他们不使用asyncawait关键字。他们只是返回一项任务。通常是Task.Factory.FromAsync之上的包装器。所以它可能安全&#34;无论如何阻止他们。