我有一个异步方法:
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
}
但是,这并不像预期的那样有效。所以我的问题是:
如何在没有DoSomethingAsync()
的情况下调用await
将始终运行并完成? (我不关心AppDomain重启/崩溃的情况)
如果我删除了async/await
中的所有DoSomethingAsync()
代码并将await
替换为.ContinueWith()
,则调用Task DoSomethingAsync()
(没有async
将调用方法声明中的1}}并确保完成(忽略大小写AppDomain重启/崩溃),如果是,则从通话中停留多长时间(我不认为如果任务我会感到高兴将在10分钟后调用)?
答案 0 :(得分:5)
你可能在DoSomethingAsync
的某个地方遇到异常,你无法观察到这是因为你忽略了这个任务。这正是您要求的行为,因为您告诉代码“忘记”任务。
要观察异常,你不能“忘记”任务:
public Task OtherMethodAsync()
{
...
return DoSomethingAsync();
}
在某些时候,await
(或Wait
)返回的任务。这就是你知道任务将运行和完成的方式。
答案 1 :(得分:4)
等待应该可以正常工作,所以这里可能还有其他东西会阻碍你正在等待的一种或多种方法。有几种可能性:
如果您可以使用VS调试器附加并观察发生的情况,请尝试暂停并查看Parallel Stacks视图。这应该有助于缩小考虑的可能性。
正如斯蒂芬所指出的那样,当你称之为“一劳永逸”时,也可能发生异常。如果您还没有,请确保处理TaskScheduler.UnobservedTaskException以记录此类事件。请注意,这是从终结器调用的,因此调用它的时间是不确定的。这可能会使调试变得棘手,因为事件可能要比导致异常的实际事件晚得多。因此,我建议遵循Stephen的建议并将任务保存到等待或稍后等待其他地方。
答案 2 :(得分:2)
ASP.NET通常不允许在请求中启动fire-and-forget(async void)操作。有关此行为的进一步说明以及一些可能的解决方法,请参阅https://stackoverflow.com/a/22484832/59641。