C# 使用 ConfigureAwait(false) 和 Task.Run 有什么区别?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14906092/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 13:25:28  来源:igfitidea点击:

What are the differences between using ConfigureAwait(false) and Task.Run?

c#.net.net-4.5async-awaitc#-5.0

提问by Sam

I understand that it's recommended to use ConfigureAwait(false)for awaits in library code so that subsequent code does not run in the caller's execution context, which could be a UI thread. I also understand that await Task.Run(CpuBoundWork)should be used instead of CpuBoundWork()for the same reason.

我了解建议在库代码中使用ConfigureAwait(false)for awaits 以便后续代码不会在调用者的执行上下文中运行,这可能是一个 UI 线程。我也明白await Task.Run(CpuBoundWork)应该使用它而不是CpuBoundWork()出于同样的原因。

Example with ConfigureAwait

示例与 ConfigureAwait

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address).ConfigureAwait(false))
    using (var responseContent = httpResponse.Content)
    using (var contentStream = await responseContent.ReadAsStreamAsync().ConfigureAwait(false))
        return LoadHtmlDocument(contentStream); //CPU-bound
}

Example with Task.Run

示例与 Task.Run

public async Task<HtmlDocument> LoadPage(Uri address)
{
    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address))
        return await Task.Run(async () =>
        {
            using (var responseContent = httpResponse.Content)
            using (var contentStream = await responseContent.ReadAsStreamAsync())
                return LoadHtmlDocument(contentStream); //CPU-bound
        });
}

What are the differences between these two approaches?

这两种方法有什么区别?

回答by Reed Copsey

In this case, your Task.Runversion will have a bit more overhead, as the first await call (await client.GetAsync(address)) will still marshal back into the calling context, as will the results of the Task.Runcall.

在这种情况下,您的Task.Run版本将有更多的开销,因为第一个 await 调用 ( await client.GetAsync(address)) 仍然会封送回调用上下文,调用的结果也是如此Task.Run

In the first example, on the other hand, your first Async()method is configured to not require marshaling back into the calling context, which allows the continuation to run on a background thread still. As such, there won't be any marshaling back into the caller's context.

另一方面,在第一个示例中,您的第一个Async()方法被配置为不需要封送回调用上下文,这允许继续在后台线程上运行。因此,不会有任何编组回到调用者的上下文中。

回答by Stephen Cleary

When you say Task.Run, you are saying that you have some CPU work to do that may take a long time, so it should always be run on a thread pool thread.

当您说 时Task.Run,您是在说您有一些 CPU 工作要做,这可能需要很长时间,因此它应该始终在线程池线程上运行。

When you say ConfigureAwait(false), you are saying that the rest of that asyncmethod does not need the original context. ConfigureAwaitis more of an optimization hint; it does not alwaysmean that the continuation is run on a thread pool thread.

当您说 时ConfigureAwait(false),您是在说该async方法的其余部分不需要原始上下文。ConfigureAwait更像是一个优化提示;它并不总是意味着延续在线程池线程上运行。

回答by Roman Gudkov

As a side note, in both cases LoadPage()could still blockyour UI thread, because await client.GetAsync(address)needs time to create a task to pass to ConfigureAwait(false). And your time consuming operation might have already started before task is returned.

作为旁注,在这两种情况下LoadPage()可能阻塞您的 UI 线程,因为await client.GetAsync(address)需要时间来创建任务以传递给 ConfigureAwait(false). 在任务返回之前,您的耗时操作可能已经开始。

One possible solution is to use SynchronizationContextRemoverfrom here:

一种可能的解决方案是SynchronizationContextRemover这里使用:

public async Task<HtmlDocument> LoadPage(Uri address)
{
    await new SynchronizationContextRemover();

    using (var client = new HttpClient())
    using (var httpResponse = await client.GetAsync(address))
    using (var responseContent = httpResponse.Content)
    using (var contentStream = await responseContent.ReadAsStreamAsync())
        return LoadHtmlDocument(contentStream); //CPU-bound
}

回答by Pankaj Rawat

Agreed @Stephen answer, If still confusion see below screenshots 1# Without ConfigureAwait(false)
See below image Main thread trying to update Label enter image description here

同意@Stephen 的回答,如果仍然困惑,请参见下面的截图 1# 没有 ConfigureAwait(false)
参见下图 主线程试图更新标签 在此处输入图片说明

2# With ConfigureAwait(false)
See below image working thread trying to update label enter image description here

2# 使用 ConfigureAwait(false)
参见下图,尝试更新标签的工作线程 在此处输入图片说明