C#中“return await”的目的是什么?
有没有这样写的方法:
public async Task<SomeResult> DoSomethingAsync() { // Some synchronous code might or might not be here... // return await DoAnotherThingAsync(); }
而不是这个:
public Task<SomeResult> DoSomethingAsync() { // Some synchronous code might or might not be here... // return DoAnotherThingAsync(); }
会有道理吗?
为什么使用return await
构造函数可以直接从内部的DoAnotherThingAsync()
调用中返回Task<T>
?
我看到在这么多地方有return await
代码,我想我应该错过了一些东西。 但据我所知,在这种情况下不使用async / await关键字,直接返回任务在function上是等价的。 为什么添加额外的await
层的额外开销?
当在正常方法中return await
时有一个偷偷摸摸的情况,在async
方法中return await
行为有所不同:当与using
(或更一般地,在try
块中的任何return await
)结合时。
考虑这两个方法的版本:
Task<SomeResult> DoSomethingAsync() { using (var foo = new Foo()) { return foo.DoAnotherThingAsync(); } } async Task<SomeResult> DoSomethingAsync() { using (var foo = new Foo()) { return await foo.DoAnotherThingAsync(); } }
第一种方法会在DoAnotherThingAsync()
方法返回时立即Dispose()
Foo
对象,这很可能早在它实际完成之前。 这意味着第一个版本可能是越野车(因为Foo
处置得太快),而第二个版本可以正常工作。
如果你不需要async
(即,你可以直接返回Task
),那么不要使用async
。
在某些情况下, return await
是有用的,就像有两个asynchronous操作一样:
var intermediate = await FirstAsync(); return await SecondAwait(intermediate);
有关async
性能的更多信息,请参阅Stephen Toub关于该主题的MSDN文章和video 。
更新:我写了一篇博客文章 ,更详细地介绍。
你想要这样做的唯一原因是,如果在前面的代码中还有其他的await
,或者在返回之前以某种方式操纵结果。 另一种可能发生的方式是通过try/catch
来改变如何处理exception。 如果你没有这样做,那么你是对的,没有理由添加使方法async
的开销。
另外一个你可能需要等待的结果是这样的:
async Task<IFoo> GetIFooAsync() { return await GetFooAsync(); } async Task<Foo> GetFooAsync() { var foo = await CreateFooAsync(); await foo.InitializeAsync(); return foo; }
在这种情况下, GetIFooAsync()
必须等待GetFooAsync
的结果,因为T
的types在两个方法之间不同, Task<Foo>
不能直接分配给Task<IFoo>
。 但是如果你等待结果,它就变成了直接分配给IFoo
Foo
。 然后,asynchronous方法只是重新包装Task<IFoo>
内的结果,并离开你去。
制作其他简单的“thunk”方法async会在内存中创build一个asynchronous状态机,而非async状态机则不会。 虽然这经常可以指出人们使用非asynchronous版本,因为它更有效率(这是真实的),这也意味着在挂起的情况下,没有证据表明该方法涉及“返回/连续堆栈”这有时使得更难理解挂起。
所以是的,当perf不重要时(通常不会),我会对所有这些thunk方法进行asynchronous处理,以便我有asynchronous状态机来帮助我稍后诊断挂起,还有助于确保如果那些thunk方法随着时间的推移而变化,他们一定会返回错误的任务而不是抛出。
这也混淆了我,我觉得以前的答案忽略了你的实际问题:
为什么使用return await构造函数可以直接从内部的DoAnotherThingAsync()调用返回Task?
那么有时你真的想要一个Task<SomeType>
,但是大多数时候你实际上需要一个SomeType
的实例,也就是任务的结果。
从你的代码:
async Task<SomeResult> DoSomethingAsync() { using (var foo = new Foo()) { return await foo.DoAnotherThingAsync(); } }
一个不熟悉语法的人(例如我)可能会认为这个方法应该返回一个Task<SomeResult>
,但是由于它被标记为async
,这意味着它的实际返回types是SomeResult
。 如果你只是使用return foo.DoAnotherThingAsync()
,你会返回一个任务,不会编译。 正确的方法是返回任务的结果,所以return await
。