已经有两个很好的答案,但要添加我的 0.02...
如果您谈论的是消耗异步操作,async/await 非常适用于 I/O 密集型和 CPU 密集型。
我认为 MSDN 文档确实略微倾向于生成异步操作,在这种情况下,您确实希望将 TaskCompletionSource(或类似的)用于 I/O 绑定和 Task.Run (或类似的)用于 CPU 绑定。创建初始 Task 包装器后,最好由async 和await使用。
对于您的特定示例,这实际上取决于LoadHtmlDocument 将花费多少时间。如果您删除Task.Run,您将在调用LoadPage 的同一上下文中执行它(可能在UI 线程上)。 Windows 8 指南规定,任何花费超过 50 毫秒的操作都应进行 async...请记住,您的开发人员计算机上的 50 毫秒可能会在客户端计算机上更长...
所以如果你能保证LoadHtmlDocument的运行时间小于50ms,你可以直接执行:
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
但是,我会推荐 ConfigureAwait @svick 提到的:
public async Task<HtmlDocument> LoadPage(Uri address)
{
using (var httpResponse = await new HttpClient().GetAsync(address)
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
using (var responseContent = httpResponse.Content)
using (var contentStream = await responseContent.ReadAsStreamAsync()
.ConfigureAwait(continueOnCapturedContext: false)) //IO-bound
return LoadHtmlDocument(contentStream); //CPU-bound
}
对于ConfigureAwait,如果HTTP 请求没有立即(同步)完成,那么(在这种情况下)这将导致LoadHtmlDocument 在线程池线程上执行,而无需显式调用Task.Run。
如果您对 async 在此级别的性能感兴趣,您应该查看 Stephen Toub 的 video 和 MSDN article 关于该主题的内容。他有大量有用的信息。