在几个月前阅读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
填充它一样)?
答案 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)任务返回方法:它们在技术上并不是异步。他们不使用async
和await
关键字。他们只是返回一项任务。通常是Task.Factory.FromAsync
之上的包装器。所以它可能安全&#34;无论如何阻止他们。