我如何等待void async
方法完成其工作?
例如,我有一个如下函数:
async void LoadBlahBlah()
{
await blah();
...
}
现在我想确保在继续其他地方之前已经加载了所有内容。
答案 0 :(得分:175)
最佳做法是仅在功能async void
标记为火灾和遗忘方法时标记,如果您要等待,则应将其标记为async Task
。
如果您仍想等待,请将其换行,如await Task.Run(() => blah())
答案 1 :(得分:53)
如果您可以将功能的签名更改为async Task
,那么您可以使用提供的代码here
答案 2 :(得分:24)
最佳解决方案是使用async Task
。您应该避免使用async void
,原因有几个,其中一个原因是可组合性。
如果方法不能返回Task
(例如,它是一个事件处理程序),那么你可以使用SemaphoreSlim
来获取方法信号退出。考虑在finally
块中执行此操作。
答案 3 :(得分:2)
执行AutoResetEvent,调用该函数然后等待AutoResetEvent,然后在知道完成后将其设置为async void。
您还可以等待从void async
返回的任务答案 4 :(得分:1)
您实际上不需要手动执行任何操作,await
关键字会暂停函数执行,直到blah()
返回。
private async void SomeFunction()
{
var x = await LoadBlahBlah(); <- Function is not paused
//rest of the code get's executed even if LoadBlahBlah() is still executing
}
private async Task<T> LoadBlahBlah()
{
await DoStuff(); <- function is paused
await DoMoreStuff();
}
T
是对象类型blah()
返回
您无法await
void
LoadBlahBlah()
功能,void
不能{{1}}
答案 5 :(得分:1)
我知道这是一个古老的问题,但这仍然是我一直遇到的问题,但是在异步void签名方法中使用async / await时,仍然没有明确的解决方案可以正确地做到这一点。
但是,我注意到.Wait()在void方法中正常工作。
并且由于异步void和void具有相同的签名,因此您可能需要执行以下操作。
void LoadBlahBlah()
{
blah().Wait(); //this blocks
}
令人困惑的是,异步/等待不会阻塞下一个代码。
async void LoadBlahBlah()
{
await blah(); //this does not block
}
当您反编译代码时,我的猜测是异步void会创建一个内部Task(就像异步Task一样),但是由于签名不支持返回该内部Tasks
这意味着内部异步void方法仍将能够“等待”内部异步方法。但外部无法知道内部任务何时完成。
所以我的结论是异步void可以按预期工作,如果需要内部Task的反馈,则需要使用异步Task签名。
希望我的漫步对任何也在寻找答案的人都有意义。
编辑: 我编写了一些示例代码并将其反编译,以查看实际情况。
static async void Test()
{
await Task.Delay(5000);
}
static async Task TestAsync()
{
await Task.Delay(5000);
}
变成(编辑:我知道主体代码不在这里,而是在状态机中,但是状态机基本上是相同的,因此我不必费心添加它们)
private static void Test()
{
<Test>d__1 stateMachine = new <Test>d__1();
stateMachine.<>t__builder = AsyncVoidMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncVoidMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
}
private static Task TestAsync()
{
<TestAsync>d__2 stateMachine = new <TestAsync>d__2();
stateMachine.<>t__builder = AsyncTaskMethodBuilder.Create();
stateMachine.<>1__state = -1;
AsyncTaskMethodBuilder <>t__builder = stateMachine.<>t__builder;
<>t__builder.Start(ref stateMachine);
return stateMachine.<>t__builder.Task;
}
AsyncVoidMethodBuilder或AsyncTaskMethodBuilder在Start方法中实际上没有任何代码可以暗示它们被阻止,并且在它们启动之后始终异步运行。
意味着没有返回的Task,将无法检查它是否完整。
按预期,它只会启动异步运行的Task,然后在代码中继续。 异步任务,首先启动任务,然后返回。
所以我想我的答案是永远不要使用异步void,如果您需要知道任务何时完成,那就是异步Task的作用。