Async Await StateMachine in ILSpy by ThinqLinq

Async Await StateMachine in ILSpy

In my Async Programming in .Net talk I like to show what’s really happening under the covers with the new async/await keywords in VS 2012. To show this, I’m currently using ILSpy instead of Reflector because it is free. I noticed an “issue” tonight when trying to locate the MoveNext method of the state machine generated class, but couldn’t find it. To begin, let’s look at the code sample.

Module AsyncWorld
    Sub DoWorkAsync()
        PrintIt()
        Console.ReadLine()
    End Sub

    Public Async Sub PrintIt()
        Dim text = "Hello World"
        Await Task.Factory.StartNew(
            Sub()
                Threading.Thread.Sleep(2000)
                Console.WriteLine(text)
            End Sub)
        Console.WriteLine("Done")
    End Sub

End Module

Ignoring the potential code smell of an Async Sub (async void in C#), let’s take a look at what IL Spy gives us out of the box for the generated classes:

image

Here we can see that the generated closure is displayed with the contained Lambda, but the underlying state machine that manages the closure is missing. If you want to see the state machine, click on Tools – Options and uncheck the “Decompile async methods (async/await)” option. 

image

Once you deselect that, refresh your project to see the compiler generated state machine:

image

My, that’s a lot of code for our simple Console Writeline task. Can’t find it? It’s called in the line

taskAwaiter = Task.Factory.StartNew(New Action(Me.$VB$ResumableLocal_$VB$Closure_ClosureVariable_1$1._Lambda$__1)).GetAwaiter().

Remember the closure we saw above? Our code’s still in there. The state machine just lets us call this asynchronously trapping for exceptions as necessary. In most cases, you don’t need to worry about all of this compiler generated code. You should be aware of it though if you are writing code with lots of awaits in a single method, particularly in tight loops. Your performance will suffer in those cases. It is better to work more natively with the TPL Task objects with continuations than using await/async in those cases. For more information, I highly recommend that you check out Steven Toub’s Zen of Async session from Build 2011.

If you want to try this out more, download my async samples including comparative examples using Callbacks, APM, Tasks, Async/Await, and Reactive Extensions (Rx).

Posted on - Comment
Categories: VB Dev Center -
comments powered by Disqus