【问题标题】:can not await async lambda不能等待异步 lambda
【发布时间】:2012-10-24 09:09:20
【问题描述】:

考虑一下,

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

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

private static async Task AwaitableMethod()
{
    await TaskEx.Delay(1000);    
}

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

await AwaitableMethod(); 

【问题讨论】:

  • AwaitableMethod 中,您实际上是在返回并调用 Wait 从 .Delay() 方法返回的任务(我假设它返回一个 Task)。在异步 lambda 中,您在 Task task 上调用 Wait。但是,我仍然没有解释。
  • 您应该非常小心将awaitWait() 混合使用。在许多情况下,这可能会导致死锁。
  • @svick 发现了一个很棒的 exampleawaitWait() 混合在一起

标签: c# task-parallel-library async-await async-ctp


【解决方案1】:

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

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

您可以避免构建一个新任务,而只需处理一个任务而不是两个:

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

【讨论】:

  • 如果第一次等待是经过大量处理后,您可能仍然需要双重任务。除了task.Result.Wait(),您还可以使用task.Unwrap().Wait()(或Unwrap&lt;T&gt;(),用于非无效方法)。新的 Task.Run 方法会自动展开,因此您只需等待预期的任务。
  • 作为一个初学者,我觉得他们可以使用async 关键字做得更好;这很令人困惑。
  • 是否可以在启动嵌套任务的情况下启动容器任务?
  • 潜在陷阱链接已损坏,现在为devblogs.microsoft.com/pfxteam/…
【解决方案2】:

您需要使用TaskEx.RunEx

它原生支持通过在内部等待内部任务在TaskPool 上运行async 方法。否则你会遇到你面临的问题,只有外部任务在等待,这显然会立即完成,留下一个仍然需要等待的任务,或者在你的情况下(甚至更糟)一个不能被期待中。

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

当前代码(固定):

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

task.Start();
var innerTask = await task;
await innerTask;

使用TaskEx.RunEx:

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

await task;

【讨论】:

  • 很好的解释,但是代码TaskEx.Run不起作用,仍然有同样的问题。
  • 啊,对不起!我正在使用 .NET 4.5... 我的意思是编写 TaskEx.RunEx。将其签名与 TaskEx.Run 进行比较 - 你会明白为什么它专门用于运行异步方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-07
  • 2016-03-25
  • 2017-10-09
  • 1970-01-01
相关资源
最近更新 更多