在我的ASP中。NET核心应用程序我有几十个以形式创建的方法
public async Task DoStuff()
{
// ...
}
所以,没有返回类型。
后来,我意识到我不小心忘记了在调用方方法中包括wait,因为async"僵尸病毒"还没有传播那么远,所以这些方法显然没有async关键字。
在执行死刑期间,没有任何不必要的后果。
问题是,当这种事情发生时,Visual Studio也不会生成警告消息,我在问自己,在这种情况下,是否真的存在忽略等待的危险?我知道等待应该自然地应用于每个异步方法,但当调用者实际上并没有返回值可供使用时,我并不真正理解这背后的原因。也许是一些捕捉异常的东西?
我还没有找到任何明确的答案,因为一般的说法是"简单地包括等待"。信不信由你,这种异步/等待的东西,我相对来说是个新手,不时地反复折磨我。
在执行过程中,没有任何不必要的后果。
我不同意。生成的代码是危险的。ASP。NET pre-Core能够检测到类似的情况并抛出异常("异步模块或处理程序在异步操作仍然挂起时完成")。由于技术原因,ASP。NET Core无法检测到这种情况,因此您不会得到";"安全网";例外,但情况本身仍然同样糟糕。
问题是,当这种事情发生时,Visual Studio也不会生成警告消息
您没有得到CS4014("因为没有等待此调用,所以在调用完成之前将继续执行当前方法。请考虑将等待运算符应用于调用的结果。"?
在这种情况下,是否真的存在放弃等待的危险?我知道等待应该自然地应用于每个异步方法,但当调用者实际上并没有返回值可供使用时,我并不真正理解这背后的原因。也许是一些捕捉异常的东西?
是的,存在危险。Task
(即使没有结果类型)用于两件事:用于调用者知道操作何时完成,以及用于调用者检测该操作的异常。
因此,一个问题是,例外被默默地吞噬了。更具体地说,async
方法的异常由async
状态机捕获,并放置在返回的Task
上,然后忽略它。
如果我自己处理上述方法中的异常(那些没有正确等待的异常),我们能说一切都很好吗?
否,因为另一个问题仍然存在:调用方不知道异步操作何时完成。这一点在ASP中尤为重要。NET,因为在操作完成之前不应发送结果。任何类型的";火与遗忘;ASP上的代码。NET在请求/响应生存期之外生存;即它的请求外部代码。
我在博客中详细介绍了为什么请求外部代码是危险的。总之,您的ASP。NET处理程序可能完成得太快,在这种情况下,请求外部代码可能会得到";丢失";。至少,它所做的一切都不会在发送响应时完成;在定期关闭(例如,滚动升级)的情况下,可能根本无法完成。