等待最后一个异步调用和返回它有区别吗? [复制]
Posted
技术标签:
【中文标题】等待最后一个异步调用和返回它有区别吗? [复制]【英文标题】:Is there a difference between awaiting the last async call and just returning it? [duplicate] 【发布时间】:2017-10-02 10:27:21 【问题描述】:查看问题标题。
换句话说,给定一个方法
async Task FrobnicateAsync() ...
两者之间是否有任何(可能是细微的)区别
async Task FrobAndFrobnicateAsync()
Frob();
await FrobnicateAsync();
和
Task FrobAndFrobnicateAsync()
Frob();
return FrobnicateAsync();
【问题讨论】:
Bill Wagner 昨天写了一封blog post,其中包含一个潜在差异示例。 另见:***.com/questions/43536642 【参考方案1】:我在eliding async 上有一篇博文。
由于您在await
之前有一个重要的Frob
,我建议您保留 async
和await
。这种方法的好处是:
async
且Frob
抛出异常,则直接抛出异常,这对消费者来说是令人惊讶的行为。即使Frob
今天没有抛出异常,明年也可以这样做;因此await
的代码更易于维护。
如果没有async
,那么Frob
不存在与FrobnicateAsync
相同的逻辑调用上下文中(假设它实际上是async
);相反,它将与FrobAndFrobnicateAsync
的调用者存在于相同的逻辑调用上下文中。在大多数代码中,这不是问题。
另见What Is the Purpose of return await?
【讨论】:
【参考方案2】:如果您字面意思显示了代码,那么您应该更喜欢return FrobnicateAsync()
版本 - 它避免了额外的状态机抽象层并且更高效。
如果您有其他东西 - 特别是任何finally
(包括using
)代码环绕return
,那么您必须确保使用await
版本,这样finally
代码直到async
任务完成之后才会发生。
如有疑问,请使用async
/await
版本。
好消息是:在它们之间切换不会影响签名(因此不是重大更改),因此您现在可以更有效地实现它,并更改为async
/await
if你发现你以后需要添加一个using
块。
作为一个额外的想法:如果你通常期望它同步完成,你可以更微妙:
Task FrobAndFrobnicateAsync()
async Task Awaited(Task t) => await t;
Frob();
var task = FrobnicateAsync();
// in .NET vFuture there will be a task.IsCompletedSuccessfully
return task.State == TaskState.RanToCompletion ? task : Awaited(task);
这避免了状态机在不需要时。
【讨论】:
我不确定我是否总是同意这一点——如果Frob
可能引发异常,那么使其异步有很大不同。请参阅 Stephen Cleary 的博文:blog.stephencleary.com/2016/12/eliding-async-await.html(在某些情况下我认为这很好,但在其他情况下则不然。)
@JonSkeet 但您并没有吸收差异; caller 应该仍然是await
-ing 或其他,所以他们会以通常的方式得到异常there
但这可能在他们的代码中完全不同。如果这是一个“调用者代码中的错误”异常(例如验证),那么我可以接受 - 如果它类似于 IOException
,那么更改它被抛出的点感觉更像是一个重大变化。
@JonSkeet 啊,您的意思是在调用FrobnicateAsync
之前FrobAndFrobnicateAsync
内部的异常?同意:这绝对是一个区别;讨论哪个版本(如果有)更正确是一个非常复杂的对话。就个人而言,无论哪种方式,我都可以接受。
另一方面,在应用程序代码中,您更有可能了解您的调用者,并能够在必要时改变他们对异常的期望:)以上是关于等待最后一个异步调用和返回它有区别吗? [复制]的主要内容,如果未能解决你的问题,请参考以下文章