繁体   English   中英

C# 调用异步方法并且从不等待返回的任务或存储对所述任务的引用的风险是什么

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM