为什么不调用Task< T> .Result死锁? [英] Why doesn't calling Task<T>.Result deadlock?

查看:75
本文介绍了为什么不调用Task< T> .Result死锁?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在阅读后,发布了一些几个月前,我对获得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 SynchronizationContexts. 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)的任务返回方法:从技术上讲,它们不是异步的.他们不使用asyncawait关键字.他们只是返回一个任务.通常是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&lt; T&gt; .Result死锁?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆