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

时间:2014-03-26 15:20:36

标签: c# .net asp.net-mvc async-await fire-and-forget

我有一个异步方法:

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

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

await DoSomethingAsync()

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

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

在这种情况下,有时任务DoSomethingAsync()会运行并完成,但有时任务从未被调用(或在await内调用某些DoSomethingAsync()但从未完成最后await SaveAsync(); })。

我试图确保通过以下代码以激烈的方式调用任务:

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

但是,这并不像预期的那样有效。所以我的问题是:

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

  2. 如果我删除了async/await中的所有DoSomethingAsync()代码并将await替换为.ContinueWith(),则调用Task DoSomethingAsync()(没有async将调用方法声明中的1}}并确保完成(忽略大小写AppDomain重启/崩溃),如果是,则从通话中停留多长时间(我不认为如果任务我会感到高兴将在10分钟后调用)?

3 个答案:

答案 0 :(得分:5)

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

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

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

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

答案 1 :(得分:4)

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

  1. 你的某个方法中有某个死锁,阻止它完成并阻止等待恢复。
  2. 由于某种原因,所有线程池线程都处于阻塞状态,导致挂起的任务无法运行。
  3. 您正在同步上下文中运行异步方法,并且正在阻止上下文,阻止它运行调度的回调。通常情况下,上下文将是UI线程,通常这很明显,因为它会锁定您的应用程序UI。
  4. 如果您可以使用VS调试器附加并观察发生的情况,请尝试暂停并查看Parallel Stacks视图。这应该有助于缩小考虑的可能性。


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

答案 2 :(得分:2)

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