问题描述
在阅读此后,发布了一些几个月前,我对获得Task<T>
的Result
感到疑惑,并用ConfigureAwait(false)
或Task.Run
不断地封装了对它的所有调用.但是,由于某种原因,以下代码成功完成了:
After reading this post a few months ago, I became paranoid of getting the Result
of a Task<T>
and incessantly wrapped all of my calls to it with a ConfigureAwait(false)
or Task.Run
. However, for some reason the following code completes successfully:
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!
3次,然后退出.这是HttpClient
特有的,可以安全地调用Result
(就像在编写它的人中用ConfigureAwait(false)
加上了代码一样)吗?
The code prints Still here!
3 times and then exits. Is this specific to HttpClient
that it is safe to call Result
on (as in the people who wrote it have peppered it with ConfigureAwait(false)
)?
推荐答案
Task.Result
仅在存在某些SynchronizationContext
的情况下才会阻止.在控制台应用程序中,没有一个,因此在ThreadPool
上安排了继续.就像您使用ConfigureAwait(false)
时一样.
Task.Result
will only block in the presence of certain SynchronizationContext
s. In console apps there isn't one so continuations are scheduled on the ThreadPool
. Just like they are when you use ConfigureAwait(false)
.
例如,在UI线程中,有一个调度到单个UI线程的继续.如果您使用UI线程与Task.Result
同步等待,那么在只能在UI线程上完成的任务上,您将陷入死锁.
In UI threads for example there is one that schedules continuations to the single UI thread. If you wait synchronously with Task.Result
using the UI thread, on a task that can only complete on the UI thread, you've got a deadlock.
此外,死锁取决于GetByteArrayAsync
的实现.如果它是一个异步方法并且其等待状态不使用ConfigureAwait(false)
,则只能进行死锁.
Moreover, a deadlock depends on the implementation of GetByteArrayAsync
. You can only deadlock if it's an async method and its awaits don't use ConfigureAwait(false)
.
如果愿意,可以使用Stephen Cleary的 AsyncContext
SynchronizationContext
到控制台应用程序,以测试您的代码是否可以在UI应用程序(或ASP.Net)中被阻止.
If you want to you can use Stephen Cleary's AsyncContext
that adds an appropriate SynchronizationContext
to your console app to test whether your code can block in UI apps (or ASP.Net).
关于HttpClient
(以及大多数.NET)的任务返回方法:从技术上讲,它们不是异步的.他们不使用async
和await
关键字.他们只是返回一个任务.通常是Task.Factory.FromAsync
的包装.因此,无论如何阻止它们都是安全的".
About HttpClient
's (and most of .NET's) Task-returning methods: they aren't technically async. They don't use the async
and await
keywords. They simply return a task. Usually a wrapper over Task.Factory.FromAsync
. So it's probably "safe" blocking them anyway.
这篇关于为什么不调用Task< T> .Result死锁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!