c#中异步函数的差异

时间:2015-04-18 21:15:26

标签: c# asynchronous task

我正在阅读C# in depth中的异步模式,我决定采用Jon的建议并对异步代码进行反编译,以实际查看发生了什么。我遇到了两个让我感到困惑的场景,为什么它们不同。

考虑这两个功能:

public static async Task<string> GetValue(){
    int count = 0;
    count++;
    string g = "asdf";
    var r = Task.FromResult<string> ("hello");
    return g;
}

并且

public static async Task<string> GetValue(){
    int count = 0;
    count++;
    string g = "asdf";
    var r = await Task.FromResult<string> ("hello");
    return g;
}

现在我希望代码输出相同的IL,因为它们都是异步函数,所以需要一个状态机。但令我惊讶的是,C#编译器确实在两种情况下创建状态机,遵循所有相同的代码,除了在第一个代码块中它没有实际保存机器中的任何信息。在第二个它存储所有变量的位置。

编译器是否有理由决定不在状态机中保存变量并根据await关键字公开两个不同的代码路径?

3 个答案:

答案 0 :(得分:2)

第一个应该给你一个关于不是真正异步的警告(&#34; ...将同步运行&#34;),因为那里没有await

因此,有一个状态机,因为您将其标记为async,并且可以使用await进行调用。

但是没有信息要保留,因为方法中没有await可以使用它。

答案 1 :(得分:1)

我认为这种差异源于缺乏await运营商。如果没有await,编译器会将您的代码视为同步代码。没有理由使用state machine

因此,本质上它会创建state machine,因为它需要asynchronous代码,但实际上并没有实现async的任何代码。这使它成为一个空容器。

  

设置代码初始化用于表示的状态机   异步方法然后使用调用将其关闭   状态机上的辅助MoveNext方法。这个状态机   type保存异步方法的状态,允许该状态   如有必要,可以在异步等待点中持久保存。

由于await,状态机会在第二个示例中保存您的数据。这会触发状态机通过多个await points持久保存数据。由于另一个例子不包含等待,它仍然是空的。它只创建了状态机,因为你把它装饰成async,尽管它确实不是。

关于此事的article的一小段摘录,希望这会有所帮助。

答案 2 :(得分:1)

只需要捕获await表达式可见的变量:

public static async Task Method() {
    int a=3;
    Console.WriteLine(a);
    {
        int b=3;
        Console.WriteLine(b);
    }
    await Task.FromResult(true);
}

例如,在捕获的a上方的代码中,未捕获b。因此,如果您不使用await,则无需捕获任何内容。