将异步委托传递给Task.Run? [复制]

Posted

技术标签:

【中文标题】将异步委托传递给Task.Run? [复制]【英文标题】:Passing an async delegate toTask.Run? [duplicate] 【发布时间】:2017-12-27 04:32:28 【问题描述】:

假设我有一个函数Task UploadAsync(Stream stream) 将一些数据上传到远程机器。调用此函数将使 async 关键字传播到整个调用树。另一种方法是将它包装在 Task.Run 中,有点像 Fire and forgot 方式:

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

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

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

【问题讨论】:

您要等UploadAsync(stream) 完成吗?顺便说一句,Task.Run 将返回 TaskUploadAsync(stream) - 将返回 Task。那么,你有什么不同?为什么你需要Task.Run 您是想异步运行它然后忘记它,还是等到任务完成?在后一种情况下,只需调用Task task = UploadAsync(stream) 然后task.Wait() 等待它完成。 Another way is to wrap it in Task.Run, kind of Fire and forgot way: 如果您实际上只想触发它并忘记它,则根本没有理由将代码包装在Task.Run 中。这增加了很多开销而没有任何回报。也就是说,一开始就解雇并忘记类似的事情几乎肯定是错误的。 “使用 Task.Run 包装和调用异步函数是一种不好的做法吗?” - 什么是“不好的做法”主要是见仁见智。我同意其他cmets,这在您的情况下毫无意义。但它是有害还是错误?这充其量取决于您未提供的上下文,并且在大多数情况下,这只是一个意见问题。毕竟,如果你要让Task.Run() 任务忽略返回的任务,你还不如自己忽略它(这很容易)。 【参考方案1】:

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

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

最好的解决方案是采用异步代码,并使用await 调用它。如果由于某种原因这不可行,那么您可以使用one of the hacks in my brownfield async article。请注意,没有适用于所有场景的 hack

例如,您可以使用 Thread Pool Hack:

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

这会将异步代码包装到后台线程中(避免deadlock problems,但也阻止异步代码使用调用上下文),并阻塞等待结果(使用GetAwaiter().GetResult()而不是Wait()/@987654329 @ 以避免在错误情况下使用 AggregateException 包装器)。

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

【讨论】:

【参考方案2】:

Task.Run(async () => await UploadAsync(stream)) 将返回一个您需要等待的任务,如果您关心等待它完成。在 Task.Run 中调用异步方法没有意义。

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

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

【讨论】:

以上是关于将异步委托传递给Task.Run? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Node.JS:如何将变量传递给异步回调? [复制]

如何将包装在 Promise 中的值传递给非异步函数? [复制]

Task.Run() 代码是不是异步执行?

在 Task.Run() 中包装同步调用以使其异步有益吗?

Task.Run 中的异步 lambda 与常规 lambda [重复]

C# 理解阻塞 UI 和异步/等待与 Task.Run 的问题?