async/await 是否适合同时受 IO 和 CPU 限制的方法? [英] Is async/await suitable for methods that are both IO and CPU bound?

查看:43
本文介绍了async/await 是否适合同时受 IO 和 CPU 限制的方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

MSDN 文档似乎声明 asyncawait 适用于 IO 绑定任务,而 Task.Run 应该用于 CPU绑定任务.

The MSDN documentation appears to state that async and await are suitable for IO-bound tasks whereas Task.Run should be used for CPU-bound tasks.

我正在开发一个应用程序,该应用程序执行 HTTP 请求以检索 HTML 文档,然后对其进行解析.我有一个看起来像这样的方法:

I'm working on an application that performs HTTP requests to retrieve HTML documents, which it then parses. I have a method that looks like this:

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
}

asyncawait 的这种使用是好的和合适的,还是我过度使用它?

Is this good and suitable use of async and await, or am I over-using it?

推荐答案

已经有两个很好的答案了,但要加上我的 0.02...

There are two good answers already, but to add my 0.02...

如果您谈论的是消耗异步操作,async/await 对 I/O 密集型和 CPU 密集型都表现出色.

If you're talking about consuming asynchronous operations, async/await works excellently for both I/O-bound and CPU-bound.

我认为 MSDN 文档确实有点倾向于产生异步操作,在这种情况下,您确实希望将 TaskCompletionSource(或类似的)用于 I/O-绑定和 Task.Run(或类似)用于 CPU 绑定.创建初始 Task 包装器后,最好由 asyncawait使用.

I think the MSDN docs do have a slight slant towards producing asynchronous operations, in which case you do want to use TaskCompletionSource (or similar) for I/O-bound and Task.Run (or similar) for CPU-bound. Once you've created the initial Task wrapper, it's best consumed by async and await.

对于您的特定示例,它实际上归结为 LoadHtmlDocument 将花费多少时间.如果删除 Task.Run,您将在调用 LoadPage(可能在 UI 线程上)的同一上下文中执行它.Windows 8 指南规定,任何需要超过 50 毫秒的操作都应该async...请记住,您的开发人员机器上的 50 毫秒在客户端机器上可能会更长...

For your particular example, it really comes down to how much time LoadHtmlDocument will take. If you remove the Task.Run, you will execute it within the same context that calls LoadPage (possibly on a UI thread). The Windows 8 guidelines specify that any operation taking more than 50ms should be made async... keeping in mind that 50ms on your developer machine may be longer on a client's machine...

所以如果你能保证LoadHtmlDocument的运行时间小于50ms,你就可以直接执行:

So if you can guarantee that LoadHtmlDocument will run for less than 50ms, you can just execute it directly:

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 提到的:

However, I would recommend ConfigureAwait as @svick mentioned:

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 的线程.

With ConfigureAwait, if the HTTP request doesn't complete immediately (synchronously), then this will (in this case) cause LoadHtmlDocument to be executed on a thread pool thread without an explicit call to Task.Run.

如果您对这个级别的 async 性能感兴趣,您应该查看 Stephen Toub 的 视频MSDN 文章 关于这个问题.他有大量有用的信息.

If you're interested in async performance at this level, you should check out Stephen Toub's video and MSDN article on the subject. He has tons of useful information.

这篇关于async/await 是否适合同时受 IO 和 CPU 限制的方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆