A method marked as async runs on the thread on which it was called until it reaches the first await keyword within it.
There is one exception though: if the method being awaited has already finished running by the time you reach the await keyword, then execution simply carries on without switching threads.
public async Task Method()
{
Console.WriteLine(1);
await Something();
Console.Writeline(2);
}
In this case, if the method is called on thread A, then 1 would be printed from thread A as well.
Then you move onto the next instruction.
If the Task returned by something has already completed, the execution continues on thread A.
If the Task returned by something is still running, then 2 could be printed from either:
- Thread A again - if there is a SynchronizationContext that enforces this (as in a WPF or WinRT application). Simply put, this is done by queuing and scheduling the remaining code (i.e., the third instruction) to be executed back on thread A.
- On a completely different thread B.
Regarding your doubts about the ThreadPool:
As we have seen, async methods are not guaranteed to run on the ThreadPool.
Only work scheduled by one of the Task.Run overload methods will surely run on the ThreadPool.
Quoting the Task MSDN doc:
Queues the specified work to run on the ThreadPool and returns a task handle for that work.
public void Task Something()
{
return Task.Run(() => Console.WriteLine(3));
}
3 will be printed by a thread on the ThreadPool.