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
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.