7

我有一个异步方法:

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()withoutawait将始终运行并完成?(我不在乎 AppDomain 重启/崩溃的情况)

  2. 如果我删除其中的所有async/await代码并DoSomethingAsync()替换await为认为如果任务将在 10 分钟后被调用,我会很高兴)?.ContinueWith()Task DoSomethingAsync()async

4

3 回答 3

5

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

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

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

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

于 2014-03-26T15:34:12.223 回答
4

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

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

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


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

于 2014-03-26T15:33:48.240 回答
2

ASP.NET 通常不允许从请求中启动即发即弃(异步无效)操作。有关此行为的进一步说明和一些潜在的解决方法,请参阅https://stackoverflow.com/a/22484832/59641

于 2014-03-26T15:45:35.960 回答