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
What are the differences between using ConfigureAwait(false) and Task.Run?
提问by Sam
I understand that it's recommended to use ConfigureAwait(false)
for await
s 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 await
s 以便后续代码不会在调用者的执行上下文中运行,这可能是一个 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.Run
version 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.Run
call.
在这种情况下,您的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 async
method does not need the original context. ConfigureAwait
is 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 SynchronizationContextRemover
from 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
同意@Stephen 的回答,如果仍然困惑,请参见下面的截图 1# 没有 ConfigureAwait(false)
参见下图 主线程试图更新标签
2# With ConfigureAwait(false)
See below image working thread trying to update label