繁体   English   中英

触发并忘记异步任务方法有时不会调用

[英]fire and forget an async Task method sometimes not invoke

我有一个异步方法:

public async Task DoSomethingAsync(){
    ...
    await ...
    await ...
    ....
    return await SaveAsync();
}

在大多数时候,我通过以下方式调用此方法:

await DoSomethingAsync()

此调用按预期工作。 但在某个地方,我需要将此方法称为火,并忘记:

public void OtherMethod()
{
    ...
    DoSomethingAsync(); //fire and forget here
}

在这种情况下,有时Task DoSomethingAsync()运行并完成,但有时任务永远不会被调用(或者在DoSomethingAsync()调用一些await但永远不会完成最后一次await SaveAsync(); )。

我正在尝试通过以下代码确保以火灾和忘记方式调用任务:

public void OtherMethod()
{
    ...
    Task.Factory.StartNew(() =>
    {
        await DoSomethingAsync();
    }); //fire and forget again here
}

但是,这不符合预期。 所以我的问题是:

  1. 如何在没有await情况下调用DoSomethingAsync()将始终运行并完成? (我不关心AppDomain重启/崩溃的情况)

  2. 如果我删除所有async/await内码DoSomethingAsync()和REPLACE await通过.ContinueWith()然后调用Task DoSomethingAsync()没有async在方法声明)将被调用,并确保完成(忽略大小写的AppDomain重新启动/崩溃),如果是的话,从通话中退出多长时间(我不认为如果在10分钟后调用任务我会很高兴)?

您可能在DoSomethingAsync某处遇到异常,由于您忽略了该任务,因此无法观察到该异常。 这正是您要求的行为,因为您告诉代码“忘记”任务。

要观察异常,你不能“忘记”任务:

public Task OtherMethodAsync()
{
  ...
  return DoSomethingAsync();
}

在某些时候, await (或Wait )返回的任务。 这就是你知道任务将运行和完成的方式。

等待应该工作正常,所以这里可能还有其他东西正在等待你的一个或多个方法。 有几种可能性:

  1. 你的某个方法中有某个死锁,阻止它完成并阻止等待恢复。
  2. 由于某种原因,所有线程池线程都被阻塞,导致挂起的任务无法运行。
  3. 您正在同步上下文中运行异步方法,并且正在阻止上下文,从而阻止它运行调度的回调。 通常情况下,上下文将是UI线程,通常这很明显,因为它会锁定您的应用程序UI。

如果您可以使用VS调试器附加并观察发生的情况,请尝试暂停并查看Parallel Stacks视图。 这应该有助于缩小考虑的可能性。


正如斯蒂芬指出的那样,当你称之为“即发即忘”时,也可能发生异常。 如果您还没有,请确保处理TaskScheduler.UnobservedTaskException以记录此类事件。 请注意,这是从终结器调用的,因此调用它的时间是不确定的。 这可能会使调试变得棘手,因为事件可能要比导致异常的实际事件晚得多。 因此,我建议遵循Stephen的建议并将任务保存到等待或稍后等待其他地方。

ASP.NET通常不允许在请求中启动fire-and-forget(async void)操作。 有关此行为的进一步说明以及一些可能的解决方法,请参阅https://stackoverflow.com/a/22484832/59641

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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