C#调用异步方法并且从不等待返回的任务或存储对所述任务的引用的风险是什么
C# what is the risk of calling an async method and never awaiting the returned task or storing references to said Task
我知道如果您从不等待返回的任务,异常处理会变得很奇怪,但是如果您实际上并不关心结果 and/or async 方法的成功,如果您不在任何地方存储对任务的引用?基本上我只是想开火而忘记方法,我想知道这样做时我需要多么迂腐。
我的具体用例是一个异步处理方法,它会等待所有未完成的任务完成 运行,然后再处理任何 HTTPClients。
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() 中是否存在任何错误风险以逃避任何 try catch 并终止我的系统?如果不是,是否存在线程 运行 foo.Dispose() 由于任务不再在范围内而放弃生命的风险?还是我懒惰编码的危险纯粹是隐藏异常?
Is there any risk of an error in foo.Dispose() escaping any try catches and killing my system if I ignore the Task?
存在无法捕获的错误,但即使您尝试处理任务中的错误,这些错误也会关闭进程。所以在实践中任务应该总是完成。
And if not, is there any risk of something like the thread running foo.Dispose() giving up on life due to the task not being in scope anymore?
不,任务将被任务调度程序引用,这将使其保持活动状态直到可以启动。一旦它是 运行 它就会被线程 运行 保持活动状态。
Or is the danger with my lazy coding purely exception hiding?
是的,据我所知最坏的效果是隐藏潜在的异常。
if you don't actually care about the results and/or the success of the async method, does it matter if you don't store a reference to the task anywhere?
任务在完成之前通常没有资格进行垃圾回收;这是因为有某种回调(将完成任务)引用该任务,并且这些回调通常是有根的(在 GC 术语中)。
当一个任务被忽略(即完成但未被观察到)时,它就有资格进行垃圾回收。如果该任务完成时出现异常,那么它会在 GC 时引发 TaskScheduler.UnobservedTaskException
。此事件曾经使进程崩溃,但现在不会了。
如果您想完全避免引发事件,那么您可以使用 FireAndForget
包装器来显式观察并忽略异常。
但是,即发即弃任务的主要问题是您的代码无法知道任务何时完成。这是整个 point 的 fire-and-forget 任务,但令人惊讶的是有多少人认为他们想要“即发即弃”但是然后要确保任务完成。这是确定何时可以安全退出进程时的常见问题。
My specific use case is an async dispose method, which waits for any outstanding tasks to finish running before it disposes any HTTPClients.
调用 dispose 作为即发即弃任务是可以的。在这种情况下不考虑关机,因为 OS 无论如何都会清理。
但是,在任务中调用 dispose 有点奇怪。处理通常非常快(就像字面上设置一两个字段),因此将工作推到后台线程没有意义。
我知道如果您从不等待返回的任务,异常处理会变得很奇怪,但是如果您实际上并不关心结果 and/or async 方法的成功,如果您不在任何地方存储对任务的引用?基本上我只是想开火而忘记方法,我想知道这样做时我需要多么迂腐。
我的具体用例是一个异步处理方法,它会等待所有未完成的任务完成 运行,然后再处理任何 HTTPClients。
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() 中是否存在任何错误风险以逃避任何 try catch 并终止我的系统?如果不是,是否存在线程 运行 foo.Dispose() 由于任务不再在范围内而放弃生命的风险?还是我懒惰编码的危险纯粹是隐藏异常?
Is there any risk of an error in foo.Dispose() escaping any try catches and killing my system if I ignore the Task?
存在无法捕获的错误,但即使您尝试处理任务中的错误,这些错误也会关闭进程。所以在实践中任务应该总是完成。
And if not, is there any risk of something like the thread running foo.Dispose() giving up on life due to the task not being in scope anymore?
不,任务将被任务调度程序引用,这将使其保持活动状态直到可以启动。一旦它是 运行 它就会被线程 运行 保持活动状态。
Or is the danger with my lazy coding purely exception hiding?
是的,据我所知最坏的效果是隐藏潜在的异常。
if you don't actually care about the results and/or the success of the async method, does it matter if you don't store a reference to the task anywhere?
任务在完成之前通常没有资格进行垃圾回收;这是因为有某种回调(将完成任务)引用该任务,并且这些回调通常是有根的(在 GC 术语中)。
当一个任务被忽略(即完成但未被观察到)时,它就有资格进行垃圾回收。如果该任务完成时出现异常,那么它会在 GC 时引发 TaskScheduler.UnobservedTaskException
。此事件曾经使进程崩溃,但现在不会了。
如果您想完全避免引发事件,那么您可以使用 FireAndForget
包装器来显式观察并忽略异常。
但是,即发即弃任务的主要问题是您的代码无法知道任务何时完成。这是整个 point 的 fire-and-forget 任务,但令人惊讶的是有多少人认为他们想要“即发即弃”但是然后要确保任务完成。这是确定何时可以安全退出进程时的常见问题。
My specific use case is an async dispose method, which waits for any outstanding tasks to finish running before it disposes any HTTPClients.
调用 dispose 作为即发即弃任务是可以的。在这种情况下不考虑关机,因为 OS 无论如何都会清理。
但是,在任务中调用 dispose 有点奇怪。处理通常非常快(就像字面上设置一两个字段),因此将工作推到后台线程没有意义。