异步等待错误的执行顺序

时间:2016-07-11 13:49:31

标签: c# asynchronous async-await

我正试图抓住异步等待模式。按照this示例,我实施了 这个小程序:

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-SynchWork For i:111

     

A-SynchWork For i:112

     

A-SynchWork For i:113

     

A-SynchWork For i:114

     

A-SynchWork For i:115

     

...

     

A-SynchWork For i:125

     

SynchWork For i:0

     

SynchWork For i:1

     

SynchWork For i:2

     

SynchWork For i:3

     

SynchWork For 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";            
}

非常感谢你。我学到了很多东西:))

2 个答案:

答案 0 :(得分:2)

只关注你的主程序:

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

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

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

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

答案 1 :(得分:1)

只需更换 asynchAwaitWork的Thread.Sleep(750);await Task.Delay(750); 事实是asynchAwaitWork开始在主线程中工作。异步工作 - 这是为了延续。使用await关键字,您可以创建continuation,这就是它开始并行工作的原因。 还要将当前线程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);来避免这种情况。