【问题标题】:async await vs TaskFactory.StartNew and WaitAll异步等待与 TaskFactory.StartNew 和 WaitAll
【发布时间】:2014-06-17 12:08:11
【问题描述】:

我有一个 NServiceBus 主机,一旦收到有关特定用户帐户的消息,它就会下载一大堆数据。一个数据文件大约 3Mb(myob - 通过 web 服务调用),另一个大约 2Mb(restful 端点,非常快!)。为避免等待太久,我将两个下载调用打包如下:

var myobBlock = Task.Factory.StartNew(() => myobService.GetDataForUser(accountId, datablockId, CurrencyFormat.IgnoreValidator));
var account = Task.Factory.StartNew(() => accountService.DownloadMetaAccount(accountId, securityContext));

Task.WaitAll(myobBlock, account);

var myobData = myobBlock.Result;
var accountData = account.Result;
//...Process AccountData Object using myobData object

我想知道与上面提到的 TPL 式方法相比,使用新的 async/await 模式有什么好处。阅读 Stephen Clearys 的笔记,似乎上述情况会导致线程坐在那里等待,而 Async/Await 将继续并释放线程以进行其他工作。

您将如何在 Async/Await 的上下文中重写它,这是否有益?我们有很多帐户要处理,但每个帐户(财年报告结束)或每个请求(当客户致电并想要他们的报告时临时)一次 MSMQ 消息

【问题讨论】:

  • GetDataForUser 和 DownloadMetaAccount 是否公开异步 api?
  • 他们没有,myobService 是第三方客户端的封装,accountservice 是我们的。
  • 您可以将 GetDataForUser 的响应包装在 TaskCompletionSource blog.stephencleary.com/2012/02/creating-tasks.html
  • 看过了,但这意味着我必须更改方法以将其装饰为运行上述代码的异步方法?我正在实现一个无法修改方法签名的接口:(
  • 您可以使用异步在 Web 服务工作期间保存三个阻塞线程。如果您不需要保存它们,异步将为您带来零收益。

标签: c# .net asynchronous task-parallel-library async-await


【解决方案1】:

使用async/await 的好处是,给定一个真正的异步 api(一个不使用 Task.Run 等通过异步调用同步方法,但真正的异步 I/O 工作),您可以避免分配任何不必要的线程,它们只是浪费资源只等待阻塞 I/O 操作。

假设您的两个服务方法都暴露了 async api,您可以执行以下操作而不是使用两个 ThreadPool 线程:

var myobBlock = myobService.GetDataForUserAsync(accountId, datablockId, CurrencyFormat.IgnoreValidator));

var account = accountService.DownloadMetaAccountAsync(accountId, securityContext));

// await till both async operations complete
await Task.WhenAll(myobBlock, account);

将会发生的情况是执行将返回给调用方法,直到两个任务都完成。当他们这样做时,如果需要,将通过 IOCP 继续到分配的SynchronizationContext

【讨论】:

  • 我发现最好从“叶子”开始,然后向外工作。您可以重新构建 Web 服务代理以获取异步方法,并将 HttpClient 用于 REST API。有了这些,让你的服务方法异步就很简单了。
  • 这是一个很好的解释 Yuval,不幸的是我没有足够的能力来支持你! @StephenCleary,有没有办法我们仍然可以使用 async/await(尤其是在 YuvalItzchakov 的解释之后)而不接触代理或休息 API?
  • @Keerthi:如果这是一个服务器,那么没有。如果这是一个客户端应用程序,那么您可以通过将东西包装在 Task.Run 中并等待它来“作弊”。另一个需要考虑的解决方案是 TPL 数据流。
  • @Keerthi 如果它足够好并且满足您的需求,您可以将其标记为答案。
猜你喜欢
  • 2015-12-13
  • 2021-09-19
  • 2014-02-21
  • 1970-01-01
  • 1970-01-01
  • 2015-09-22
  • 2013-02-15
  • 1970-01-01
相关资源
最近更新 更多