简体   繁体   中英

differences in async functions in c#

I was reading about the async pattern in C# in depth , and I decided to take Jon's advice and decompile the async code to actually see what was going on. And I came across two scenarios that confused me a bit as to why they were different.

Consider these two functions:

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

And

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

Now I'd expect the code to ouput the same IL being that they are both async functions so there needs to be a state machine. But to my surprise the C# compiler does create the statemachine in both cases follows all the same code as one would expect, except in the first code block it doesn't actually save any information in the machine. Where in the second it does store all the variables.

Is there a reason that the compiler decides to not save the variables in the state machine and expose two different code paths based on the await keword?

The first one should have given you a warning about not really being async ("... will run synchronously") because there is no await in there.

So there is a state machine because you marked it async and it could be called with await .

But there is no information to keep because there is no await inside the method that would use it.

I believe the disparity stems from the lack of the await operator. Without the await the compiler is treating your code as synchronous code. Which has no reason to utilize the state machine .

So in essence it creates the state machine as it expects asynchronous code, but you do not actually implement any code that is async . Which keeps it as an empty container.

The setup code initializes the state machine used to represent the asynchronous method and then kicks it off using a call to the secondary MoveNext method on the state machine. This state machine type holds state for the asynchronous method, allowing that state to be persisted across asynchronous await points , if necessary.

The State Machine holds your data in your second example because of the await . This triggers the State Machine to persist the data through multiple await points . Since the other example doesn't contain await, it remains empty. It only created the State Machine because you decorated it as async though it really isn't.

A small excerpt from an article on the matter, hopefully this helps.

Only variable, that visible by await expression need to be captured:

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

For example, in code above a captured, b not captured. So, if you does not use await , nothing need to be captured.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM