等待Task.Run实际上并不等待

时间:2019-01-23 13:18:31

标签: c# async-await

我试图绕过异步等待,但是我写了一个小测试,无法理解我得到的结果。

考虑以下代码(WPF应用程序,在MainWindow内部):

private async void Button_Click(object sender, RoutedEventArgs e)
{
    Stopwatch l_Stopwatch = new Stopwatch();

    Debug.WriteLine("Entering Button_Click...");

    l_Stopwatch.Start();

    await DoSomethingAsync();

    l_Stopwatch.Stop();

    Debug.WriteLine("DoSomethingAsync completed in {0}", l_Stopwatch.ElapsedMilliseconds);

    l_Stopwatch.Restart();

    await DoSomethingElseAsync();

    l_Stopwatch.Stop();

    Debug.WriteLine("DoSomethingElseAsync completed in {0}", l_Stopwatch.ElapsedMilliseconds);
}

private async Task DoSomethingAsync()
{
    Debug.WriteLine("Doing something Async");

    await Task.Delay(5000);

}

private async Task DoSomethingElseAsync()
{
    await Task.Run((Action)(async () => { 
        Debug.WriteLine("Doing something else Async");

        await Task.Delay(5000);
    }));
}

我希望DoSomethingElseAsync在继续之前等待〜5000ms,但是我不断收到以下消息

Entering Button_Click...
Doing something Async
DoSomethingAsync completed in 5005
Doing something else Async
DoSomethingElseAsync completed in 3

因此,在这一点上,我认为有些根本的东西我不了解异步等待方式...

有人能照亮吗?

1 个答案:

答案 0 :(得分:3)

问题在这里:

await Task.Run((Action)(async () => { 
    Debug.WriteLine("Doing something else Async");

    await Task.Delay(5000);
}));

您强制转换为Action代表,该代表不返回任何内容且无法等待(因为Task返回了Action,因此没有void可以等待)。

您可以将代码更改为:

await Task.Run(async () => { 
    Debug.WriteLine("Doing something else Async");

    await Task.Delay(5000);
});

OR

您可以强制转换为Func<Task>的委托,该委托返回可以等待的Task

await Task.Run((Func<Task>)(async () => { 
    Debug.WriteLine("Doing something else Async");

    await Task.Delay(5000);
}));

其他信息:

如果看到编译器生成的代码(SharpLab),您将得到不同之处:

  • 当您强制转换为Action时,编译器会创建AsyncVoidMethodBuilder
  • 当您强制转换为Func<Task>或不强制所有编译器创建时 AsyncTaskMethodBuilder