When your code falls into an await expression (assuming that the expected was not executed synchronously), control returns to the calling method, as if you had written return; .
(it returns a Task<T> that the caller can use to wait for the async part to complete)
Then the calling method will continue to execute until it returns (it usually returns immediately, like it, await returned task) and so on until it reaches the top (stack).
As soon as it hits the top of the call stack, this thread will do what it naturally does.
If it is a user interface thread, it will return to the message loop, preserving the user interface.
If it is a ThreadPool thread (or an ASP.Net workflow), it will return to the pool and wait (synchronously) for more work.
If it is a raw thread (main thread in a console application or new Thread() , it will be terminated.
source share