How C# async and await actually work
How do `async` and `await` work in C#? What happens to the method and its thread when execution reaches an `await`?
what they're testing: The interviewer is probing whether you can reason about nonblocking control flow, task completion, and when threads are actually involved.
async lets the compiler turn a method into a resumable state machine. await marks a possible suspension point; it does not request a new thread. An ordinary Task-returning async method starts synchronously on the calling thread and runs until it awaits an incomplete operation. If the operation is already complete, execution continues immediately.
For an incomplete awaitable, the state machine preserves the state needed later and arranges a continuation. The method returns an incomplete task to its caller, so the current thread does not wait. When the operation completes, the continuation resumes the method. await then produces the result or propagates the exception, and the returned task completes when the method finishes.
async and await do not make work parallel. Asynchronous I/O can remain pending without blocking a thread. CPU-bound work still needs a thread; Task.Run can move suitable work to the thread pool. Awaiting a Task may capture a synchronization context or nondefault task scheduler and use it to schedule the continuation. With no such context or scheduler, code must not assume it resumes on the original thread. Prefer Task or Task<T> over async void, except for event handlers.
Where people slip
the tempting wrong answer, and what's actually true
Every `async` method starts on a new thread.
Calling an ordinary Task-returning async method begins executing it synchronously; the keywords alone do not create a thread.
`await` blocks the current thread until the task finishes.
Awaiting an incomplete task suspends the method and returns control to its caller without blocking the current thread.
Execution always switches threads when it reaches `await`.
A completed awaitable continues synchronously, and a suspended continuation may later run on the same thread or another thread depending on its context and scheduler.
`async void` is equivalent to `async Task` when no value is returned.
An `async void` call cannot be awaited and does not expose its completion or exceptions through a task, so it is mainly for event handlers.
If they push further
What happens when the task is already complete at the await point?
The method continues synchronously without suspending, and `await` immediately produces the result or throws the task's exception.
When should `Task.Run` be used with async code?
Use it to offload suitable CPU-bound work, especially away from a UI thread. Do not wrap naturally asynchronous I/O in `Task.Run` just to make it look asynchronous.
What does `ConfigureAwait(false)` change?
It tells the awaiter not to force the continuation back through the captured context. It does not guarantee a thread switch, because an already-completed awaitable can still continue inline.
Sources
- Microsoft Learn: await operator ↗learn.microsoft.com
- Microsoft Learn: Asynchronous programming scenarios ↗learn.microsoft.com
- Microsoft Learn: Async return types ↗learn.microsoft.com
- .NET Blog: How Async/Await Really Works in C# ↗devblogs.microsoft.com
- .NET Blog: ConfigureAwait FAQ ↗devblogs.microsoft.com
Now answer it yourself.
Reading a strong answer is easy. Producing one under pressure is the skill the interview tests. Gapmap grades your answer against the same bar an interviewer would.
beta
The interviewer part is in the works.
The diagnostic, personal maps, and AI mock interviews are being finished right now. The notes stay free either way. Leave an email and you'll get the first-cohort invite, plus a month of Pro when it opens.