首页 > 解决方案 > 这是异步流程的工作原理吗

问题描述

我是 C# 异步编程的新手,并且已经阅读了几篇关于它的好文章(参见这里这里这里的例子)。我想我知道它是如何工作的,但我希望有人能确认我走在正确的轨道上。

如果我理解正确,异步编程是这样工作的:

将关键字 async 添加到一个方法中,以表明它将离开并做自己的事情,而与程序的其余部分正在做什么无关。这基本上就像一个厨师让一个预备厨师去切蘑菇、洋葱和胡萝卜。

async 方法分配给类型为 Task 的任务。Task 是正在运行的方法,或者在我们的例子中是准备厨师。返回类型是任务将返回的类型。一旦分配了任务,当前方法就会忽略它,知道它正在处理。

await 命令是调用方法请求任务结果的地方。继续我们的例子,厨师向预备厨师要切碎的蔬菜。如果Task已经完成,则给出结果,调用方法继续运行。如果任务尚未完成,调用方法必须等待它完成。换句话说,如果在厨师需要蔬菜的时候准备厨师还没有完成切菜,那么厨师必须等待才能继续制作食谱。(我知道,这个比喻在这里不成立,因为真正的厨师会去做其他事情,但这只是为了简化解释。)

要使用 await 命令,方法必须是异步方法。在上面的示例中,调用方法是异步方法。因此,当它遇到 await 命令时,控制会返回到它的调用方法,该方法将继续运行,直到它完成或遇到它自己的 await。

所以,我们现在得到的是方法A调用异步方法B,它调用异步方法C。方法B在await上停止,等待方法C的结果。方法A和C现在都在异步运行,而方法B是等待结果。一旦方法 C 返回结果,然后方法 A 和 B 将异步运行,直到方法 B 完成,或者方法 A 决定它需要等待方法 B 的结果。请注意,方法 B 可能不需要返回结果,因此方法 A 可能在方法 B 之前完成。

这听起来对吗,或者控制从 A 到 B,然后只有在等待被命中时才返回 A?因此,如果 A 没有自己的等待,它将在控制权返回 B 之前完成。

我意识到我在有更多复杂性的地方过于简单化了,但我试图在细节之前理解这些概念。

标签: c#asynchronousasync-await

解决方案


任何时候await都使用,该方法在该点编译成一个单独的方法,原始方法在该点完成(async/await是语法糖)。Task生成的方法被注册为await引用的 的延续。如果给定方法中存在多个await,则相同的过程适用于每个await.

任何时候async用来描述一个方法,就意味着该方法支持await并且可以编译成一系列的延续。该方法的第一部分与调用代码内联调用,但作为 an 的一部分生成的部分await将排队到 TPL 的默认调度程序(按顺序,随着部分完成)并根据该调度程序的配置方式进行调用。Task从方法返回的Aasync将代表整个方法(因此该方法可以在await方法内的任何位置取消),并且如果/当完成时,注册到该方法的任何延续Task都将排队到 TPL 的默认调度程序Task

在你的类比中,厨师更像是一个线程而不是一个方法。我会使用术语“烹饪动作”来描述方法和延续,如果同时完成任何两个烹饪动作,那是因为厨师已将这些动作委托给副厨师长(另一个线程),除非有没有可用的副厨师长,在这种情况下,厨师以后只能自己做。

异步/等待

public void Main()
{
    var result = Calculate(1, 3).Result;

    async Task<int> Calculate(int a, int b)
    {
        var c = await Add(a, 5);
        var d = await Add(b, 3);

        return await Add(c, d);
    }

    async Task<int> Add(int a, int b)
    {
        return a + b;
    }
}

纯 TPL

public void Main()
{
    const int a = 1;
    const int b = 3;

    var t1 = Task.Run(() => new
        {
            c = a + 5
        }
    );

    var t2 = t1.ContinueWith(t =>
        new
        {
            c = t.Result.c,
            d = b + 3
        }
    );

    var t3 = t2.ContinueWith(t =>
        t.Result.c + t.Result.d
    );

    var result = t3.Result;
}

推荐阅读