[英]C# what is the risk of calling an async method and never awaiting the returned task or storing references to said Task
我知道如果您从不等待返回的任务,异常处理会变得很奇怪,但是如果您实际上并不关心异步方法的结果和/或成功,那么如果您不存储对任何地方的任务? 基本上我只想解雇并忘记方法,我想知道这样做时我需要多么迂腐。
我的具体用例是一个异步处理方法,它在处理任何 HTTPClient 之前等待任何未完成的任务完成运行。
public async Task Dispose(){
try{
...
}catch{} //might add some minimal logging, but probably wont
}
按照懒惰的降序排列,我一直在考虑的实现是
public void DisposeFoo(){
foo.Dispose()//feed the task to the void
}
以上安全性比
private Task DisposeFooTask;
public void DisposeFoo(){
DisposeFooTask= foo.Dispose()//store the task and never touch it again
}
而且我还在 SO 上找到了这种方法
static async void FireAndForget(this Task task)
{
try
{
await task;
}
catch (Exception e)
{
// log errors
}
}
public void DisposeFoo(){
foo.Dispose().FireAndForget();
}
如果我忽略任务,foo.Dispose() escaping 是否存在任何尝试捕获并杀死我的系统的风险? 如果没有,是否存在运行 foo.Dispose() 之类的线程由于任务不在 scope 中而放弃生命的风险? 还是我的懒惰编码的危险纯粹是隐藏异常?
如果您实际上并不关心异步方法的结果和/或成功,那么是否不在任何地方存储对任务的引用是否重要?
任务在完成之前通常没有资格进行垃圾收集; 这是因为存在引用该任务的某种回调(将完成任务),并且这些回调通常是有根的(在 GC 术语中)。
当一个任务被忽略(即完成但未观察到)时,它就可以进行垃圾收集。 如果该任务以异常完成,那么它将在 GC 时引发TaskScheduler.UnobservedTaskException
。 此事件用于使进程崩溃,但不再如此。
如果您想完全避免引发事件,则可以使用FireAndForget
包装器显式观察并忽略异常。
但是,即发即弃任务的主要问题是您的代码无法知道任务何时完成。 这就是“即发即弃”任务的全部意义所在,但令人惊讶的是,有多少人认为他们想要“即发即弃”,但又想确保任务完成。 在确定何时可以安全退出进程时,这是一个常见问题。
我的具体用例是一个异步处理方法,它在处理任何 HTTPClient 之前等待任何未完成的任务完成运行。
调用 dispose 作为一个即发即弃的任务就可以了。 在这种情况下,关闭不是考虑因素,因为无论如何操作系统都会清理。
但是,在任务中调用 dispose 有点奇怪。 处理通常非常快(就像字面上设置一两个字段一样),因此将这项工作推送到后台线程是没有意义的。
如果我忽略任务,foo.Dispose() escaping 是否存在任何尝试捕获并杀死我的系统的风险?
存在无法捕获的错误,但即使您尝试处理任务中的错误,这些错误也会关闭进程。 因此,在实践中,任务应该始终完成。
如果没有,是否存在运行 foo.Dispose() 之类的线程由于任务不在 scope 中而放弃生命的风险?
不,任务将由任务调度程序引用,这将使其保持活动状态,直到可以启动为止。 一旦它运行,它就会被运行它的线程保持活动状态。
还是我的懒惰编码的危险纯粹是隐藏异常?
是的,据我所知,最坏的影响是隐藏潜在的例外情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.