首页 > 解决方案 > 在仅返回 Task 的异步方法上使用 await

问题描述

在我的 ASP.NET Core 应用程序中,我以以下形式创建了几个(十几个)方法

public async Task DoStuff() 
{ 
   // ...
}

所以,没有返回类型。

后来,我意识到我不小心忘记在调用者方法中到处都包含 await (显然没有 async 关键字,因为异步“僵尸病毒”还没有传播那么远)。

在执行期间,没有任何不良后果。

问题是,当这种情况发生时,Visual Studio 也不会生成任何警告消息,我问自己,在这种情况下是否真的存在忽略等待的危险?我知道 await 应该自然地应用于每个 async 方法,但是当调用者实际上没有要使用的返回值时,我真的不明白这背后的原因。也许有捕捉异常的东西?

我还没有找到任何明确的答案,因为一般性声明是“简单地包含等待”。信不信由你,这个我相对较新的异步/等待的东西,不时地反复咬我。

标签: c#.netasynchronous.net-coreasync-await

解决方案


在执行期间,没有任何不良后果。

我不同意。生成的代码很危险。ASP.NET pre-Core 能够检测到类似情况并引发异常(“异步模块或处理程序已完成,而异步操作仍处于挂起状态”)。由于技术原因,ASP.NET Core 无法检测到这种情况,因此您不会遇到“安全网”异常,但情况本身仍然很糟糕。

问题是,当这种事情发生时,Visual Studio 也不会生成任何警告消息

您没有得到CS4014(“因为没有等待此调用,所以在调用完成之前继续执行当前方法。考虑将 await 运算符应用于调用结果。”)

在这种情况下,实际上是否存在忽略等待的危险?我知道 await 应该自然地应用于每个 async 方法,但是当调用者实际上没有要使用的返回值时,我真的不明白这背后的原因。也许有捕捉异常的东西?

是的,有危险。Task(即使没有结果类型)用于两件事:让调用者知道操作何时完成,以及让调用者检测该操作的异常。

所以,一个问题是异常被默默地吞没了。更具体地说,async方法中的异常被状态机捕获async并放置在返回的Task中,然后被忽略。

如果我自己处理上述方法中的异常(未正确等待的异常),那么我们可以说一切都很好吗?

不,因为另一个问题仍然存在:调用者不知道异步操作何时完成。在 ASP.NET 中了解这一点尤为重要,因为在操作完成之前不应发送结果。ASP.NET 上的任何“即发即弃”代码都存在于请求/响应生命周期之外;即,它是请求外部代码。

我在我的博客上详细介绍了为什么请求外部代码是危险的。总之,您的 ASP.NET 处理程序可能过早完成,在这种情况下,请求外部代码可能会“丢失”。至少,在发送响应时,它所做的任何事情都不会完成;并且在定期关闭的情况下(例如,滚动升级),它可能根本无法完成。


推荐阅读