无法等待异步lambda

ken*_*yzx 62 c# task-parallel-library async-await async-ctp

想想这个,

Task task = new Task (async () =>{
    await TaskEx.Delay(1000);
});
task.Start();
task.Wait(); 
Run Code Online (Sandbox Code Playgroud)

调用task.Wait()不等待任务完成,下一行立即执行,但如果我将async lambda表达式包装到方法调用中,代码将按预期工作.

private static async Task AwaitableMethod()
{
    await TaskEx.Delay(1000);    
}
Run Code Online (Sandbox Code Playgroud)

然后(根据svick的评论更新)

await AwaitableMethod(); 
Run Code Online (Sandbox Code Playgroud)

Joe*_*ley 82

在lambda示例中,当您调用时task.Wait(),您正在等待您构造的新任务,而不是它返回的延迟任务.要获得所需的延迟,您还需要等待生成的任务:

Task<Task> task = new Task<Task>(async () => {
    await Task.Delay(1000);
});
task.Start();
task.Wait(); 
task.Result.Wait();
Run Code Online (Sandbox Code Playgroud)

你可以避免构建一个新的Task,只需要一个Task来处理而不是两个:

Func<Task> task = async () => {
    await TaskEx.Delay(1000);
};
task().Wait();
Run Code Online (Sandbox Code Playgroud)

  • 我强烈建议阅读[在传递异步lambdas时避免的潜在陷阱](http://blogs.msdn.com/b/pfxteam/archive/2012/02/08/10265476.aspx)和[Task.Run vs Task. Factory.StartNew](http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx). (9认同)
  • 潜在的陷阱链接已损坏,现在为 https://devblogs.microsoft.com/pfxteam/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/ (6认同)
  • 作为初学者,我觉得他们可以用`async`关键字做得更好; 这很令人困惑. (5认同)

Law*_*eld 6

你需要使用TaskEx.RunEx.

它本身支持在内部等待内部任务的运行async方法TaskPool.否则你将遇到你正面临的问题,只有等待外部任务,这显然立即完成,留下一个仍然需要等待的任务,或者在你的情况下(甚至更糟)一个无法实现的无效lambda期待已久的.

或者,您可以等待任务两次,前提是您正确构建了外部任务(目前您还没有).

当前代码(固定):

Task task = new Task<Task>(async () =>{
    await TaskEx.Delay(1000);
});

task.Start();
var innerTask = await task;
await innerTask;
Run Code Online (Sandbox Code Playgroud)

使用TaskEx.RunEx:

Task task = TaskEx.RunEx(async () =>{ // Framework awaits your lambda internally.
    await TaskEx.Delay(1000);
});

await task;
Run Code Online (Sandbox Code Playgroud)

  • 唉,对不起!我正在使用.NET 4.5 ...我打算编写TaskEx.RunEx.将其签名与TaskEx.Run进行比较 - 您将看到它专门用于运行异步方法的原因. (2认同)