首页 文章

在等待期间控制多个任务的流程

提问于
浏览
3

当我有两个任务并等待一个任务时,我无法理解控制流程 . Control Flow in Async Programs (C# and Visual Basic)只使用一个等待,所以它没有帮助 .

我有以下代码:

public async Task Loop(string name, int count)
{
    for (int i = 0; i < count; i++)
    {
        Console.WriteLine("{0}: {1} Before", name, i);
        await Task.Delay(10);
        Console.WriteLine("{0}: {1} After", name, i);
    }
    Console.WriteLine("{0} COMPLETE", name);
}

[TestMethod]
public async Task TwoLoopsWithSeparateAwait()
{
    var loopOne = Loop("ONE", 3);
    Console.WriteLine("After ONE Creation");
    var loopTwo = Loop("TWO", 3);
    Console.WriteLine("After TWO Creation, before ONE await");
    await loopOne;
    Console.WriteLine("After ONE await");
    await loopTwo;
    Console.WriteLine("After TWO await");
}

结果如下:

  • ONE:0之前

  • 一次创作后

  • TWO:0之前

  • 在TWO创建之后,在ONE等待之前

  • TWO:0之后

  • TWO:1之前

  • ONE:0之后

  • ONE:1之前

  • ONE:1之后

  • ONE:2之前

  • TWO:1之后

  • TWO:2之前

  • TWO:2之后

  • 两个完整

  • ONE:2之后

  • ONE COMPLETE

  • 等待一个人之后

  • 等待两个人之后

根据await (C# Reference)

await表达式不会阻止它正在执行的线程 . 相反,它会导致编译器将其余的异步方法注册为等待任务的延续 . 然后,Control返回到异步方法的调用者 . 当任务完成时,它会调用它的继续,异步方法的执行从它停止的地方恢复 .

我理解在等待loopOne之前会发生什么,但我认为只有loopOne会被执行(可能是同步的),看起来await的行为更像是一个可以继续保存可能任务列表的yield(我认为它符合“当任务时”完成后,它会调用它的继续“) .

在等待多个任务期间,控制流程背后的逻辑是什么?

1 回答

  • 6

    async 方法同步执行,直到达到 await . 然后,它创建一个任务,代表您正在等待的其余代码的操作,作为操作完成时执行的延续 . 这意味着在 async 方法中,当达到第一个 await 时,控件实际上通过热任务返回给调用者 . 当在该延续内部达到 await 时,它再次注册延续,依此类推 .

    所以在你的情况下,执行顺序应该是:

    • 第一个循环的同步部分 .

    • 第二个循环的同步部分 .

    • 第一个循环的延续

    • 第二个循环的延续 .

    • ......

    • 第一个循环后调用者的继续 .

    • 第二个循环后调用者的继续 .

    根据异步操作实际花费的时间长短,中间的延续可以很容易地处于不同的顺序 .

    你可以想象这里有3种不同的流程 . 第一个执行两个 Loop 调用的同步部分,启动2个并发的 async 操作和continuation流,然后在第一个调用中注册一个延续,它将向第二个调用注册延续 .

相关问题