Answers:
Slaks和Killercam的答案很好。我以为我会添加更多上下文。
您的第一个问题本质上是关于可以标记哪些方法async
。
标为A的方法
async
可以返回void
,Task
或Task<T>
。它们之间有什么区别?
一个Task<T>
返回异步方法可以等待,并在任务完成时,它会毫无顾忌了一个T.
一个Task
返回异步方法可以等待,而当任务完成时,任务的延续计划运行。
甲void
返回异步方法不能等待; 这是一种“解雇”的方法。它确实是异步工作的,您无法知道何时完成。这有点奇怪。正如SLaks所说,通常只有在创建异步事件处理程序时才这样做。事件触发,处理程序执行;没有人会“等待”事件处理程序返回的任务,因为事件处理程序不会返回任务,即使它们返回了,什么代码也可以将任务用于某些任务?首先,通常不是用户代码将控制权转移到处理程序。
在评论中,您的第二个问题实质上是关于可以await
编辑的内容:
可以采用哪种方法
await
?可以使用返回空洞的方法await
吗?
不可以,无法等待返回空隙的方法。编译器将转换await M()
为对的调用M().GetAwaiter()
,其中GetAwaiter
可能是实例方法或扩展方法。等待的价值必须是您可以获得等待者的价值;显然,返回空值的方法不会产生可用于获得等待者的值。
Task
-返回方法可以产生等待的值。我们期望第三方将希望创建自己的Task
可以等待的对象的实现,而您将能够等待它们。然而,你将不会被允许申报async
方法是什么回报,但是void
,Task
还是Task<T>
。
(更新:我的最后一句话可能被C#的未来版本所伪造;有人建议允许异步方法的任务类型以外的返回类型。)
(更新:上面提到的功能使它进入了C#7。)
async void
方法SynchronizationContext
在开始执行时就处于活动状态,从而引发异常。这类似于(同步)事件处理程序的行为。@DrewMarsh:UnobservedTaskException
和运行时设置仅适用于“解雇”异步Task方法,而不适用于async void
方法。
如果呼叫者想等待任务或添加继续。
实际上,返回的唯一原因void
是由于编写事件处理程序而无法返回Task
。
void
,则您将无法执行其生成的任务。(其实,我不知道是否即使产生Task
的话)
方法返回Task
,并Task<T>
是可组合的-这意味着你可以await
在他们里面的的async
方法。
async
返回void
的方法是不可组合的,但是它们还有两个其他重要属性:
当你处理与保持上下文的第二点是很重要的计数的异步操作的。
ASP.NET上下文就是这样一种上下文。如果使用异步Task
方法而没有从异步方法等待它们void
,则ASP.NET请求将太早完成。
另一个上下文是AsyncContext
我为单元测试编写的(可在此处获得)-该AsyncContext.Run
方法跟踪未完成的操作计数,并在操作计数为零时返回。
类型Task<T>
是任务并行库(TPL)的主力类型,它表示“ T
将来会产生类型结果的某些工作/工作”的概念。非通用Task类型表示“将来会完成但没有结果的工作”的概念。
精确地将如何产生类型的结果T
是特定任务的实现细节;TPL任务通常从当前进程中的线程池中移植到工作线程中,但是实现细节不是该Task<T>
类型的基础;TPL任务通常被移植到本地计算机上的另一个进程,另一个线程等。而是Task<T>
可以表示产生的任何高延迟操作T
。
根据您上面的评论:
该await
表达式的意思是“评估该表达式以获得代表将来将要产生结果的工作的对象。将当前方法的其余部分注册为与该任务的继续相关的回调。一旦产生了该任务并进行了回调已注册,请立即将控制权返还给我的呼叫者”。这与常规方法调用相反/相反,常规方法调用的意思是“记住您在做什么,运行此方法直到其完全完成,然后从您中断的地方开始,现在就知道该方法的结果”。
编辑:我应该在2011年10月的《 MSDN杂志》中引用Eric Lippert的文章,因为这对我一开始就了解这些东西有很大帮助。
有关负载的更多信息和白页,请参见此处。
我希望这会有所帮助。