返回 void 和返回任务有什么区别?
在查看各种 C# 异步 CTP 示例时,我看到一些返回 void
的异步函数,以及其他返回非泛型 Task
的异步函数。我可以理解为什么在异步操作完成时返回 Task
对于将数据返回给调用者很有用,但是我看到的函数的返回类型为 Task< /code> 从不返回任何数据。为什么不返回
void
?
In looking at various C# Async CTP samples I see some async functions that return void
, and others that return the non-generic Task
. I can see why returning a Task<MyType>
is useful to return data to the caller when the async operation completes, but the functions that I've seen that have a return type of Task
never return any data. Why not return void
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
SLAks 和 Killercam 的答案很好;我想我应该添加更多背景信息。
您的第一个问题本质上是关于哪些方法可以标记为异步。
可以等待返回异步方法的
Task
,当任务完成时,它将提供一个 T。可以等待返回异步方法的
Task
,并且当 任务完成时,它会提供一个 T。任务完成后,计划继续运行该任务。无法等待返回异步方法的
void
;这是一种“一劳永逸”的方法。它确实是异步工作的,你无法知道它何时完成。这有点奇怪。正如 SLaks 所说,通常您只会在创建异步事件处理程序时才这样做。事件触发,处理程序执行;没有人会“等待”事件处理程序返回的任务,因为事件处理程序不返回任务,即使它们返回任务,什么代码会使用任务来执行某些操作?通常不是用户代码首先将控制权转移给处理程序。您在评论中的第二个问题本质上是关于可以等待什么:
不,不能等待返回 void 的方法。编译器将
await M()
转换为对M().GetAwaiter()
的调用,其中GetAwaiter
可能是实例方法或扩展方法。等待的值必须是您可以获得等待者的值;显然,返回 void 的方法不会产生可以从中获取等待者的值。Task
- 返回方法可以生成可等待的值。我们预计第三方将希望创建自己的可等待的类似任务的对象的实现,并且您将能够等待它们。但是,您将不允许声明返回除void
、Task
或Task
async 方法。 >。(更新:我的最后一句话可能会被未来版本的 C# 伪造;有一项提议允许异步方法使用除任务类型之外的返回类型。)
(更新:上面提到的功能已纳入 C# 7。)
SLaks and Killercam's answers are good; I thought I'd just add a bit more context.
Your first question is essentially about what methods can be marked
async
.A
Task<T>
returning async method can be awaited, and when the task completes it will proffer up a T.A
Task
returning async method can be awaited, and when the task completes, the continuation of the task is scheduled to run.A
void
returning async method cannot be awaited; it is a "fire and forget" method. It does work asynchronously, and you have no way of telling when it is done. This is more than a little bit weird; as SLaks says, normally you would only do that when making an asynchronous event handler. The event fires, the handler executes; no one is going to "await" the task returned by the event handler because event handlers do not return tasks, and even if they did, what code would use the Task for something? It's usually not user code that transfers control to the handler in the first place.Your second question, in a comment, is essentially about what can be
await
ed:No, a void-returning method cannot be awaited. The compiler translates
await M()
into a call toM().GetAwaiter()
, whereGetAwaiter
might be an instance method or an extension method. The value awaited has to be one for which you can get an awaiter; clearly a void-returning method does not produce a value from which you can get an awaiter.Task
-returning methods can produce awaitable values. We anticipate that third parties will want to create their own implementations ofTask
-like objects that can be awaited, and you will be able to await them. However, you will not be allowed to declareasync
methods that return anything butvoid
,Task
orTask<T>
.(UPDATE: My last sentence there may be falsified by a future version of C#; there is a proposal to allow return types other than task types for async methods.)
(UPDATE: The feature mentioned above made it in to C# 7.)
如果调用者想要等待任务或添加延续。
事实上,返回
void
的唯一原因是您无法返回Task
,因为您正在编写事件处理程序。In case the caller wants to wait on the task or add a continuation.
In fact, the only reason to return
void
is if you cannot returnTask
because you're writing an event handler.返回
Task
和Task
的方法是可组合的 - 这意味着您可以在async
方法内await
它们。返回
void
的async
方法不可组合,但它们确实有两个其他重要属性:当您处理维护未完成异步操作计数的上下文时,第二点很重要。
ASP.NET 上下文就是这样一种上下文;如果您使用异步
Task
方法而不从异步void
方法等待它们,则 ASP.NET 请求将过早完成。另一个上下文是我为单元测试编写的
AsyncContext
(可在此处) -AsyncContext.Run
方法跟踪未完成的操作计数并在其为零时返回。Methods returning
Task
andTask<T>
are composable - meaning that you canawait
them inside of anasync
method.async
methods returningvoid
are not composable, but they do have two other important properties:The second point is important when you're dealing with a context that maintains a count of outstanding asynchronous operations.
The ASP.NET context is one such context; if you use async
Task
methods without awaiting them from an asyncvoid
method, then the ASP.NET request will be completed too early.Another context is the
AsyncContext
I wrote for unit testing (available here) - theAsyncContext.Run
method tracks the outstanding operation count and returns when it's zero.类型
Task
是任务并行库 (TPL) 的主力类型,它代表“某些工作/作业将产生T
T在未来”。 “将来将完成但不返回结果的工作”的概念由非泛型 Task 类型表示。确切地说,
T
类型的结果将如何生成,以及特定任务的实现细节;工作可能会分派给本地计算机上的另一个进程、另一个线程等。TPL 任务通常分派给当前进程中线程池中的工作线程,但该实现细节对于来说并不是基础任务
类型;相反,Task
可以表示任何产生T
的高延迟操作。根据上面的评论:
await
表达式的意思是“计算此表达式以获取表示将来将产生结果的工作的对象。注册当前方法的其余部分作为与该任务的继续相关联的回调。一旦该任务生成并且回调被注册,立即将控制权返回给我的调用者”。这与常规方法调用相反/相反,常规方法调用意味着“记住您正在做什么,运行此方法直到完全完成,然后从您上次停下的地方继续,现在知道该方法的结果”。编辑:我应该引用 Eric Lippert 在 2011 年 10 月 MSDN 杂志上的文章,因为这对我理解这些东西有很大帮助。
要加载更多信息和白页,请参阅 此处。
我希望这有一些帮助。
Type
Task<T>
is the workhorse type of the Task Parallel Library (TPL), it represents the concept of "some work/job that is going to produce a result of typeT
in the future". The concept of "work that will complete in the future but returns no result" is represented by the non-generic Task type.Precisely how the result of type
T
is going to be produced is and implementation detail of a particular task; the work might be farmed out to another process on the local machine, to another thread etc. TPL tasks are typically farmed out to worker threads from a thread pool in the the current process, but that implementation detail is not fundamental to theTask<T>
type; rather aTask<T>
can represent any high-latency operation that produces aT
.Based on your comment above:
The
await
expression means "evaluate this expression to obtain an object representing work that will in future produce a result. Sign up the remainder of the current method as the call back associated with the continuation of that task. Once that task is produced and the call back is signed up, immediately return control to my caller". This is opposed/in contrast to a regular method call, which means "remember what you're doing, run this method until it is completely finished and then pick up where you left off, now knowing the result of the method".Edit: I should cite Eric Lippert's article in October 2011 MSDN Magazine as this was a great help to me in understanding this stuff in the first place.
For loads more infromation and whitepages see here.
I hope this is of some help.