1
Reply

How does async/await work under the hood?

Manav Pandya

Manav Pandya

Jul 22
775
2
Reply

    # What happens when you write async/await?What happens when you write async/await?

    When you write something like:

    1. public async Task<int> GetDataAsync()
    2. {
    3. var result = await CallExternalApiAsync();
    4. return result + 1;
    5. }

    The C# compiler does not just make it “multithreaded.” Instead:

    • The compiler rewrites your method into a state machine (like how iterators work with yield return).

    • Each await is a checkpoint where the method can pause and resume later.

    • The method doesn’t block the thread. Instead, it returns a Task immediately.

    How does await work internally?How does await work internally?

    await checks if the awaited task is already completed:

    • If yes — continue execution synchronously.

    • If no — register a continuation callback (what to do when the task finishes) and return control to the caller.

    The continuation is scheduled to run on a SynchronizationContext (UI thread in WPF/WinForms, request context in ASP.NET) or on the ThreadPool if no context is captured.

    Example Transformation

    This:

    1. var data = await CallExternalApiAsync();
    2. Console.WriteLine(data);

    Is transformed roughly into:

    1. CallExternalApiAsync()
    2. .GetAwaiter()
    3. .OnCompleted(() =>
    4. {
    5. var data = task.Result; // resume execution
    6. Console.WriteLine(data);
    7. });

    So instead of blocking, it sets up a callback to resume later.

    Execution Flow

    • Caller calls GetDataAsync() it runs until the first await.

    • At await, it:

      • Checks if task is done → if not, attach a continuation.

      • Returns a Task to the caller.

    • When CallExternalApiAsync() finishes:

      • It signals its completion.

      • The continuation runs → method resumes from the await.

    • Eventually, the outer Task<int> completes with the result.

    Threading ClarificationThreading Clarification

    • async/await does not create new threads.

    • If work is I/O bound (HTTP, file, DB call), the thread is released until the result is ready.

    • If work is CPU-bound, you’d use Task.Run to move it to a background thread.

    In ASP.NET Core

    • There’s no SynchronizationContext like classic ASP.NET.

    • Continuations just run on the ThreadPool.

    • This avoids deadlocks that used to happen in old ASP.NET when mixing .Result and await.

    Key takeaway for interviews:

    • async/await = compiler-generated state machine.

    • await = non-blocking checkpoint that sets up a continuation.

    • Execution resumes when the awaited task completes.

    • It’s about asynchronous programming, not about creating threads.