嵌套异步等待不等待

时间:2014-07-13 01:13:45

标签: c# asynchronous task async-await

我想我错过了解c#中async await的行为。

我有两种方法可以返回Task定义为

的方法
public async Task Name()
{
await AsyncOperation() 
}

想象AsyncOperation()就像PostAsync HttpClient一样。

现在我在其他方法中调用它们

public asyn Task Method()
{
await Name1(() => { "bla bla"});
await Name2();
Console.WriteLine("Continue");
}

这对我来说是预期的。等到Name1()Name2()完成然后继续。

现在我需要嵌套Name1()Name2()。实际上Name1()是一个请求等待窗口,它接收lambda参数是一个缓慢的操作,而Name2()是一个缓慢的文件下载。我希望在下载文件时出现Plese Wait窗口。

所以我尝试这样的事情:

public asyn Task Method()
{
    await Name1( async ()=>
    {
        await Name2();
    }
    Console.WriteLine("Continue");
}

在这种情况下,执行不会等待untile Name2()完成。为什么会发生这种情况并await不等待?

更新

这是请等待的方法背后的逻辑。它使用Mahapps Dialogs显示Please Wait消息,执行lambda收到的代码,然后关闭请等待消息。

public static async Task Name1(Action longOperation)
{
    _progressController = await _metroWindow.ShowProgressAsync("Please wait...");            
    await Task.Run(() => longOperation());
    await _progressController.CloseAsync();
}

2 个答案:

答案 0 :(得分:5)

Name1方法接受委托并返回Task<T>,其中T是委托返回的类型。在您的情况下,委托会返回Task,因此我们会得到Task<Task>作为结果。使用await只等待外部任务的完成(它立即返回内部任务),然后忽略内部任务。

你可以通过在lambda函数中删除async和await来解决这个问题。

另外,请查看Asynchronous Gotchas in C#

答案 1 :(得分:-1)

Name1期望有一个动作参数,但是您真正想要的是一个func。换句话说,Name1应该看起来像这样:

public static double Name1(Func<Task> longOperation)
{
    longOperation().Wait();
}

或者,将操作包装在函子中,然后等待。

public static double Name1(Action longOperation)
{
    Func<Task> f = async () => { longOperation(); };
    f.Wait();
}

如果您等待异步子,则子将在后台运行,但不会阻止调用方法的继续执行。

如果要执行子程序并等待其完成,然后再继续下游逻辑,则将异步子程序转换为异步函数(当没有实际返回值时,结果类型为threading.tasks.task)。

此站点上有一些很好的例子,这些例子说明了人们在异步等待中犯的常见错误: https://devblogs.microsoft.com/pfxteam/potential-pitfalls-to-avoid-when-passing-around-async-lambdas/