异步等待错误的执行顺序

本文关键字:执行 顺序 错误 等待 异步 | 更新日期: 2023-09-27 17:56:25

我正在尝试掌握异步等待模式。按照此示例,我实现了这个小程序:

private async void asynchWork()
{
    // Line 1
    Task<string> readTask = asynchAwaitWork();
    // Line 2
    synchWork();
    // Line 3
    string result = await readTask;
    // Line 4
    Debug.WriteLine(result);
    Debug.WriteLine("The End");
}
private void synchWork()
{
    for (int i = 0; i < 5; i++)
    {
        Debug.WriteLine("SynchWork For i : " + i);
        Thread.Sleep(750);
    }
}
private async Task<string> asynchAwaitWork()
{
    for (int i = 0; i < 15; i++)
    {
        Debug.WriteLine("A-SynchWork For i : " + (i+111));
        Thread.Sleep(750);
    }
    return "finished";
}

我预计第 1 行被执行,然后第 2 行和第 4 行将不得不等到 3 行完成并返回一个字符串。但是查看输出,synchWork方法在asynchWork方法之后执行。

A 同步工作 i : 111

A 同步工作 i : 112

A 同步工作 i : 113

A 同步工作 i : 114

A 同步工作 i : 115

A 同步工作 i : 125

同步工作 i : 0

同步工作 i : 1

同步工作 i : 2

同步工作 i : 3

同步工作 i : 4

完成

结束

我预计 synchWork 方法将在 asynchWork 方法繁忙并在第 3 行等待结果时执行。我在示例中误解了什么?还是只是 Debug.WriteLine 的输出最终是按顺序执行的,但真正的工作顺序是根据我的期望?

编辑:在评论和答案的帮助下,我学到了:

  • 不要忽视警告并研究它们的含义;)

  • 使用 await 关键字可以等待由方法中创建的Task执行的操作的结果。

编辑2:

  • 但是任务必须开始!否则将没有并行处理,编译器将通过主线程追逐它,并且第 3 行实际上只有第 4 行的阻塞函数,而不是更多。

由于Thread.Sleep(750)只是一个模拟工作,我真的不需要Delay这也有效:

private async Task<string> asynchAwaitWork()
{
    await Task.Run(()=> {
        for (int i = 0; i < 15; i++)
            {
                Debug.WriteLine("A-SynchWork For i : " + (i+111));
                Thread.Sleep(750);
            }
            });
    return "finished";            
}

谢谢。我学到了很多:)

异步等待错误的执行顺序

只看你的主程序:

当第 3 行执行时,您可以保证在第 1 行中获得的任务已完成执行其中的任何内容。

在第 2 行,您无法保证任务已开始执行或已完成。您不知道它是否会并行运行。您只知道有一个任务可以计划执行。

您在函数asynchAwaitWork中创建的任务的实现是完全同步的。该实现细节导致它在返回最终(在本例中为立即)返回字符串的 Task 时完全完成打印内容。

请注意,您创建的任务不会打印任何内容。在当前实现中打印"A-SynchWork For i"消息是创建任务的副作用。

只需替换 Thread.Sleep(750); 在 asynchAwaitWork await Task.Delay(750);问题是 asynchAwaitWork 开始在主线程中工作。异步工作 - 这是为了延续。使用 await 关键字,您可以创建延续,这就是它开始并行工作的原因。此外,将当前线程 ID 添加到输出中,以查看会发生什么。例:

private async void asynchWork()
{
    // Line 1
    Task<string> readTask = asynchAwaitWork();
    // Line 2
    synchWork();
    // Line 3
    string result = await readTask;
    // Line 4
    Debug.WriteLine(result);
    Debug.WriteLine("The End");
}
private void synchWork()
{
    for (int i = 0; i < 5; i++)
    {
        Debug.WriteLine("SynchWork For i : " + i + " and thareadId = " + Thread.CurrentThread.ManagedThreadId);
        Thread.Sleep(750);
    }
}
private async Task<string> asynchAwaitWork()
{
    for (int i = 0; i < 15; i++)
    {
        Debug.WriteLine("A-SynchWork For i : " + (i + 111) + " and thareadId = " + Thread.CurrentThread.ManagedThreadId);
        await Task.Delay(750);
        //Thread.Sleep(750);
    }
    return "finished";
}

如前所述,如果创建了 Task.Delay(750),它将使用相同的同步上下文。例如,如果您从 WPF 运行代码

[STAThread]
void Main()
{
    var window = new Window();
    window.Loaded += (s, e) => {
        asynchWork();
    };
    window.ShowDialog();
}

您将看到所有内容都发生在同一个线程中。因此,请注意这一点,您可以使用await Task.Delay(750).ConfigureAwait(false);来避免这种情况。