我是否总是必须等待一次性对象的异步方法而不是返回其任务?
c#
似乎我陷入了一个巨大的陷阱,经过数小时的调试,我看到该过程超出了 RunGame1() 中的“使用”范围,并且任务在等待时从未完成。
async void Execute(object o) // ICommand.Execute
{
// fire and forget
try
{
await RunGame2(); // RunGame1() fails to complete
}
finally
{ ... }
}
// This fails due to process going out of "using" scope and never completes
Task RunGame1()
{
var info = new ProcessStartInfo("game.exe") { CreateNoWindow = true };
using var process = new Process() { StartInfo = info };
process.Start();
return process.WaitForExitAsync();
}
// Have to await the Task inside the method
async Task RunGame2()
{
var info = new ProcessStartInfo("game.exe") { CreateNoWindow = true };
using var process = new Process() { StartInfo = info };
process.Start();
await process.WaitForExitAsync();
}
是否有解决此问题的模式,以便我可以返回 Task 以保存编译器制作额外的状态机,还是只是需要注意的事情?
回答
这确实是一个常见的问题 - 由于相似,我已经看到了几个错误。
简而言之:
- 不,您并不总是需要执行
await任务,有时避免异步机制的开销可能会非常有利 - 特别是在像文件/网络 IO 循环这样的紧凑代码中,但是(而且它是一个很大的但是) - 如果这意味着你逸出
try/finally地区(也包括using和lock,虽然有其他更大的问题与lock在async代码),那么你需要考虑到这一点,这通常意味着“是的,你需要await”
如果有一个分析器在这样的区域内发现非方法return中的Task[<T>]/会很好,因为它几乎总是一个错误,并且有几次它不是(那里没有什么可处理被退回的东西)它可以被压制。ValueTask[<T>]asyncfinally