Which thread runs the code after await?

Read the explanation
What if

FetchAsync starts on the caller's thread. After await Task.Delay, the rest of it, and of Main, runs on a thread-pool thread.

Predict first

Main starts on thread 1 and awaits Task.Delay inside FetchAsync. Which thread runs the code after the await?

012345678thread 1: Main startsMainthread 1: FetchAsync startsFetchwaits for Main's Task to finishpool thread: FetchAsync resumesresumespool thread: return "data"returnpool thread: Main resumesMain

Tap any block to see what that thread is doing.

  • Running
  • Waiting / parked
Step 1/5

Main starts on thread 1.

1public static async Task Main()2{3    Log("Main starts");4    string data = await FetchAsync();5    Log($"Main resumes with {data}");6}7 8static async Task<string> FetchAsync()9{10    Log("FetchAsync starts"); // still the caller's thread11    await Task.Delay(100); // a network call: no thread waits for it12    Log("FetchAsync resumes"); // a thread-pool thread13    return "data";14}

Explanation

What just happened

Main started on thread 1 and called FetchAsync, which ran on that same thread up to its await. Task.Delay needs no thread while it waits: FetchAsync returned to its caller, and a timer resumed it later. The rest of FetchAsync, and then Main, ran on a thread-pool thread, not thread 1.

Try the what-if switch

Why

await splits a method in two: the part before runs now, the part after is scheduled when the awaited task finishes. Where that second part runs depends on the SynchronizationContext. A console app has none, so it runs on the pool.

Watch out

Don’t assume you’re on the same thread after await. Anything tied to the thread, like [ThreadStatic] fields or ThreadLocal<T> values, can be different on the other side.

Common questions

Does await create a new thread in C#?

No. The code before the first await runs on the caller's thread. While the awaited work is pending, the method has returned to its caller; when it completes, the rest runs on whichever thread the context picks.

Which thread runs the code after await?

In a console app, a thread-pool thread: there's no SynchronizationContext to return to. In a UI app, the context posts it back to the UI thread.

When should I use Task.Run?

For CPU-bound work you want off the current thread. Task.Run queues it on the thread pool; awaiting it frees the caller until it's done.

Verified: this timeline matches a real program, checked in CI on .NET 8 and 10. How we verify. Unclear or wrong? Tell us