返回void和返回任务有什么区别?

时间:2011-11-07 22:07:55

标签: c# asynchronous task-parallel-library return-type async-ctp

在查看各种C#异步CTP示例时,我看到一些返回void的异步函数,以及其他返回非泛型Task的函数。我可以看到为什么返回Task<MyType>对于异步操作完成时将数据返回给调用者很有用,但是我看到的返回类型为Task的函数永远不会返回任何数据。为什么不返回void

4 个答案:

答案 0 :(得分:199)

SLaks和Killercam的答案很好;我以为我只是添加了一些上下文。

您的第一个问题主要是关于可以标记哪些方法async

  

标记为async的方法可以返回voidTaskTask<T>。它们之间有什么区别?

可以等待Task<T>返回异步方法,当任务完成时,它将提供一个T.

可以等待Task返回异步方法,当任务完成时,计划继续执行任务。

无法等待void返回异步方法;这是一种“火与死”的方法。它确实异步工作,你无法告诉它什么时候完成。这有点奇怪;正如SLaks所说,通常你只会在制作异步事件处理程序时这样做。事件触发,处理程序执行;没有人会“等待”事件处理程序返回的任务,因为事件处理程序不返回任务,即使他们这样做了,什么代码会使用Task来做什么?通常不是用户代码首先将控制转移到处理程序。

您的第二个问题,在评论中,主要是关于await编辑的内容:

  

await可以使用哪种方法?空洞返回方法可以await编辑吗?

不,无法等待返回空洞的方法。编译器将await M()转换为对M().GetAwaiter()的调用,其中GetAwaiter可能是实例方法或扩展方法。等待的价值必须是你可以得到一个等待者的价值;显然,返回空隙的方法不会产生一个可以获得等待的值。

Task - 返回方法可以产生等价值。我们预计第三方将希望创建自己的Task实现 - 类似于可以等待的对象,您将能够等待它们。但是,除了asyncvoidTask之外,您不会声明Task<T>方法返回任何内容。

(更新:我的最后一句话可能会被未来的C#版本伪造;有一项建议允许异步方法的任务类型以外的返回类型。)

(更新:上面提到的功能进入了C#7。)

答案 1 :(得分:22)

如果调用者想要等待任务或添加延续。

事实上,返回void的唯一原因是,如果无法返回Task,因为您正在编写事件处理程序。

答案 2 :(得分:18)

返回TaskTask<T>的方法是可组合的 - 这意味着您可以在await方法中async使用它们。

返回async

void方法不可组合,但它们还有其他两个重要属性:

  1. 它们可以用作事件处理程序。
  2. 它们代表“顶级”异步操作。
  3. 当您处理维护未完成异步操作的计数的上下文时,第二点非常重要。

    ASP.NET上下文就是这样一个上下文;如果您使用异步Task方法而不等待异步void方法,那么ASP.NET请求将过早完成。

    另一个上下文是我为单元测试编写的AsyncContext(可用here) - AsyncContext.Run方法跟踪未完成的操作计数,并在它为零时返回。

答案 3 :(得分:12)

类型Task<T>是任务并行库(TPL)的主力类型,它表示“将来会产生T类型结果的某些工作/作业”的概念。 “通用将在未来完成但不返回结果”的概念由非通用任务类型表示。

确切地说,如何生成类型T的结果是特定任务的实现细节;可能会将工作转移到本地计算机上的另一个进程,另一个线程等.TPL任务通常从当前进程中的线程池中移植到工作线程,但该实现细节不是{{1 }};相反,Task<T>可以表示产生Task<T>的任何高延迟操作。

根据您的上述评论:

T表达式意味着“计算此表达式以获取表示将来生成结果的工作的对象。将当前方法的其余部分注册为与该任务的延续相关联的回调。生成该任务并注册回叫,立即将控制权返回给我的呼叫者“。这与常规方法调用相反/相反,这意味着“记住你正在做的事情,运行这个方法直到它完全完成然后从你离开的地方开始,现在知道方法的结果”。


编辑:我应该引用Eric Lippert在2011年10月的MSDN杂志上的文章,因为这对我理解这些东西起了很大帮助。

对于负载更多的信息和白页,请参阅here

我希望这会有所帮助。