将异步委托传递给Task.Run?

时间:2017-07-21 08:05:05

标签: c# asynchronous

假设我有一个函数Task UploadAsync(Stream stream)将一些数据上传到远程机器。调用此函数将使异步关键字扩展整个调用树。另一种方法是将它包装在Task.Run中,有点火和忘记方式:

void DoUpload(Stream stream) {Task.Run(async () => await UploadAsync(stream)})}

我从Stephen Cleary的blog读到,说Task.Run只能用于CPU绑定操作,显然上传一大块数据不受CPU限制。所以,如果我在await UploadAsync(stream)内拨打Task.Run似乎是错误的方式。

所以我的问题是,使用Task.Run来包装和调用异步函数是不好的做法吗?

2 个答案:

答案 0 :(得分:1)

  

调用此函数将使异步关键字传播整个调用树。

是的,这是异步代码的重点。 If you call an asynchronous function synchronously, then it's not asynchronous

最佳解决方案是采用异步代码,并使用await进行调用。如果由于某种原因,这不可行,那么您可以使用one of the hacks in my brownfield async article。请注意,没有适用于每种情况的黑客

例如,您可以使用线程池黑客:

Task.Run(() => UploadAsync(stream)).GetAwaiter().GetResult();

这将异步代码包装到后台线程中(避免deadlock problems,但也阻止异步代码使用调用上下文),并阻塞等待结果(使用GetAwaiter().GetResult()代替{{ 1}} / Wait()以避免错误情况下的Result包装器。)

但请注意exposing a synchronous wrapper for asynchronous methods is an antipattern。因此,提供以这种方式实现的AggregateException方法将是一种糟糕的设计。

答案 1 :(得分:0)

meshdata.indices.pushback(v0); // one of the original indices meshdata.indices.pushback(m0); // one of the new ones meshdata.indices.pushback(m2); // ... 将返回您需要等待的任务,如果您关心等待它完成。在Task.Run中调用异步方法毫无意义。

你可以在任务上调用.Wait(),这将阻止线程直到请求完成。

异步调用确实有“感染”整个调用树的倾向,但我还没有找到任何可行的方法来避免这种情况。