我知道建议在库代码中对await
使用ConfigureAwait(false)
,这样后续代码就不会在调用者的执行上下文中运行,而执行上下文可能是UI线程。出于同样的原因,我也理解应该使用await Task.Run(CpuBoundWork)
而不是CpuBoundWork()
。
使用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
}
使用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
});
}
这两种方法有什么不同?
发布于 2013-02-16 10:10:00
在这种情况下,您的Task.Run
版本将有更多的开销,因为第一个等待调用(await client.GetAsync(address)
)仍将编组回调用上下文,Task.Run
调用的结果也是如此。
另一方面,在第一个示例中,您的第一个Async()
方法被配置为不需要封送回调用上下文,这使得context仍然可以在后台线程上运行。这样,就不会有任何编组回到调用者的上下文中。
发布于 2017-05-07 13:03:24
同意@Stephen回答,如果仍然困惑,请参阅下面的屏幕截图,不带ConfigureAwait的1# (False)
请参见下图尝试更新标签的主线程
带有ConfigureAwait的2# (False)
如下图所示,工作线程正在尝试更新标签
https://stackoverflow.com/questions/14906092
复制相似问题