public async Task DoSomethingAsync(){ ... await ... await ... .... return await SaveAsync(); }
await DoSomethingAsync()
此调用按预期工作.但在某个地方,我需要将此方法称为火,并忘记:
public void OtherMethod() { ... DoSomethingAsync(); //fire and forget here }
在这种情况下,有时Task DoSomethingAsync()会运行并完成,但有时任务永远不会被调用(或在DoSomethingAsync()中调用一些等待但永远不会完成最后一次等待SaveAsync();).
public void OtherMethod() { ... Task.Factory.StartNew(() => { await DoSomethingAsync(); }); //fire and forget again here }
但是,这不符合预期.所以我的问题是:
>如何在没有等待的情况下调用DoSomethingAsync()将始终运行并完成? (我不关心AppDomain重启/崩溃的情况)
>如果我删除DoSomethingAsync()中的所有异步/等待代码并用.ContinueWith()替换await,那么将调用Task DoSomethingAsync()(方法声明中没有异步)的调用并确保完成(忽略大小写AppDomain重启) /崩溃),如果是的话,从通话中退出多长时间(我不认为如果在10分钟后调用任务我会很高兴)?
解决方法
>你的某个方法中有某个死锁,阻止它完成并阻止等待恢复.
>由于某种原因,所有线程池线程都阻塞,阻止挂起的任务运行.
>您正在同步上下文中运行异步方法,并且正在阻止上下文,阻止它运行调度的回调.通常情况下,上下文将是UI线程,通常这很明显,因为它会锁定您的应用程序UI.
如果您可以使用VS调试器附加并观察发生的情况,请尝试暂停并查看Parallel Stacks视图.这应该有助于缩小考虑的可能性.
正如斯蒂芬指出的那样,当你称之为“即发即忘”时,也可能发生异常.如果您还没有,请确保您处理TaskScheduler.UnobservedTaskException以记录此类事件.请注意,这是从终结器调用的,因此调用它的时间是不确定的.这可能会使调试变得棘手,因为事件可能要比导致异常的实际事件晚得多.因此,我建议遵循Stephen的建议并将任务保存到等待或稍后等待其他地方.