c# - 在仅返回 Task 的异步方法上使用 await
问题描述
在我的 ASP.NET Core 应用程序中,我以以下形式创建了几个(十几个)方法
public async Task DoStuff()
{
// ...
}
所以,没有返回类型。
后来,我意识到我不小心忘记在调用者方法中到处都包含 await (显然没有 async 关键字,因为异步“僵尸病毒”还没有传播那么远)。
在执行期间,没有任何不良后果。
问题是,当这种情况发生时,Visual Studio 也不会生成任何警告消息,我问自己,在这种情况下是否真的存在忽略等待的危险?我知道 await 应该自然地应用于每个 async 方法,但是当调用者实际上没有要使用的返回值时,我真的不明白这背后的原因。也许有捕捉异常的东西?
我还没有找到任何明确的答案,因为一般性声明是“简单地包含等待”。信不信由你,这个我相对较新的异步/等待的东西,不时地反复咬我。
解决方案
在执行期间,没有任何不良后果。
我不同意。生成的代码很危险。ASP.NET pre-Core 能够检测到类似情况并引发异常(“异步模块或处理程序已完成,而异步操作仍处于挂起状态”)。由于技术原因,ASP.NET Core 无法检测到这种情况,因此您不会遇到“安全网”异常,但情况本身仍然很糟糕。
问题是,当这种事情发生时,Visual Studio 也不会生成任何警告消息
您没有得到CS4014(“因为没有等待此调用,所以在调用完成之前继续执行当前方法。考虑将 await 运算符应用于调用结果。”)?
在这种情况下,实际上是否存在忽略等待的危险?我知道 await 应该自然地应用于每个 async 方法,但是当调用者实际上没有要使用的返回值时,我真的不明白这背后的原因。也许有捕捉异常的东西?
是的,有危险。Task
(即使没有结果类型)用于两件事:让调用者知道操作何时完成,以及让调用者检测该操作的异常。
所以,一个问题是异常被默默地吞没了。更具体地说,async
方法中的异常被状态机捕获async
并放置在返回的Task
中,然后被忽略。
如果我自己处理上述方法中的异常(未正确等待的异常),那么我们可以说一切都很好吗?
不,因为另一个问题仍然存在:调用者不知道异步操作何时完成。在 ASP.NET 中了解这一点尤为重要,因为在操作完成之前不应发送结果。ASP.NET 上的任何“即发即弃”代码都存在于请求/响应生命周期之外;即,它是请求外部代码。
我在我的博客上详细介绍了为什么请求外部代码是危险的。总之,您的 ASP.NET 处理程序可能过早完成,在这种情况下,请求外部代码可能会“丢失”。至少,在发送响应时,它所做的任何事情都不会完成;并且在定期关闭的情况下(例如,滚动升级),它可能根本无法完成。
推荐阅读
- javascript - 在 Django 中使用 SweetAlert2
- python - 如何用python用字符串的总和制作金字塔
- html - 如何与元素交互,而不是与它的伪元素子元素交互?
- stored-procedures - 不能写 if 或 select 上面的程序开始
- python - 如何在matplotlib上获得科学记数法的乘数字符串
- linux - 服务器:名称或服务未知 BIND9
- python - 一行解决一些 Python 正则表达式任务
- python - 查找和绘制边界框
- php - 使用 file_put_contents 表单的白名单用户
- routes - 在 Vaadin Flow 中的路由之间传递自定义对象