All demos

How async/await becomes a state machine

Follow an async C# method through compiler transformation, MoveNext calls, suspension at await, continuation scheduling, and Task completion.

Current stage Ready
Step0 / 7
State
Returned Tasknot created
Executing threadcaller thread
Stored awaiternone

Source async method

This is the code we write.

async Task<string> LoadProfileAsync()
{
    Log("start");
    var user = await GetUserAsync();
    var score = await GetScoreAsync(user);
    return $"{user}: {score}";
}

Compiler-generated state machine

The struct lives across suspensions and keeps local variables as fields.

var machine = new <LoadProfileAsync>d__0();
machine.MoveNext();
state = 0; builder.AwaitUnsafeOnCompleted(...);
awaiter.GetResult(); state = -1;
state = 1; builder.AwaitUnsafeOnCompleted(...);
state = -2; builder.SetResult(result);

Runtime flow

The thread is released while I/O is pending; the state machine preserves progress.

1Caller
2MoveNext()
3User I/O
4Continuation queue
5Score I/O
6SetResult()

The method has not been called yet. No state machine or Task exists.