Sam*_*Sam 40 c# asynchronous async-await c#-5.0
MSDN文档看起来指出async并await适合于IO密集型任务,而Task.Run应该用于CPU密集型任务.
我正在处理一个执行HTTP请求以检索HTML文档的应用程序,然后解析它.我有一个看起来像这样的方法:
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())
return await Task.Run(() => LoadHtmlDocument(contentStream)); //CPU-bound
}
Run Code Online (Sandbox Code Playgroud)
这是好的和适当的使用async和await,或者我是否过度使用它?
Ste*_*ary 40
已经有两个很好的答案,但要添加我的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将运行少于50毫秒,您可以直接执行它:
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
}
Run Code Online (Sandbox Code Playgroud)
但是,我建议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
}
Run Code Online (Sandbox Code Playgroud)
使用ConfigureAwait,如果HTTP请求没有立即(同步)完成,那么这将(在这种情况下)导致LoadHtmlDocument在线程池线程上执行而没有显式调用Task.Run.
如果您async对此级别的性能感兴趣,请查看Stephen Toub 关于此主题的视频和MSDN文章.他有大量有用的信息.
Ser*_*rvy 19
它适用于await任何异步操作(即由a表示Task).
关键点在于,对于IO操作,只要有可能,您希望使用提供的方法,即非常核心的异步方法,而不是使用Task.Run阻塞同步方法.如果在执行IO时阻塞线程(甚至线程池线程),则不会充分利用await模型的实际功能.
一旦创建了Task代表您的操作,就不再关心它是CPU还是IO绑定.对于调用者来说,它只是需要进行的一些异步操作await.
svi*_*ick 18
有几件事需要考虑:
Task.Run()可能是一个好主意.虽然代码的用户可以自己做,如果他们想要的话.Task.Run()而不是直接运行代码会产生一些开销,但如果操作实际需要一些时间,那么它应该不重要.(此外,返回同步上下文会有一些开销,这是您应该在库代码中使用ConfigureAwait(false)大多数awaits的另一个原因.)加权,我认为使用await Task.Run()是正确的选择.它确实有一些开销,但也有一些优点,这可能是重要的.
| 归档时间: |
|
| 查看次数: |
14105 次 |
| 最近记录: |