This is simultaneous, in the sense that many outstanding asynchronous operations can be performed at any time. It may or may not be multithreaded.
By default, await schedule a continuation to the "current execution context". The "current execution context" is defined as SynchronizationContext.Current if it is not null or TaskScheduler.Current if there is no SynchronizationContext .
You can override this default behavior by calling ConfigureAwait and passing false for the continueOnCapturedContext parameter. In this case, the continuation will not be returned to this execution context. This usually means that it will be launched in the threadpool thread.
If you are not writing library code, the default behavior is exactly what you need. WinForms, WPF, and Silverlight (i.e., all user interface interfaces) supply the SynchronizationContext , so the continuation is done in the user interface thread (and can safely access user interface objects). ASP.NET also provides a SynchronizationContext , which ensures that the continuation runs in the correct request context.
Other threads (including threadpool, Thread and BackgroundWorker threads) do not supply a SynchronizationContext . Therefore, console applications and Win32 services do not have a SynchronizationContext by default. In this situation, the continuation is performed in threadpool threads. This is why the Console demo daemon using await / async involves calling Console.ReadLine / ReadKey or locking Wait on a Task .
If you need a SynchronizationContext , you can use the AsyncContext from my Nito.AsyncEx library; it basically just provides an async compatible "main loop" using a SynchronizationContext . I find this useful for console applications and unit tests (VS2012 now has built-in support for async Task unit tests).
For more information about SynchronizationContext see my February MSDN article .
DoEvents no means DoEvents or equivalent call; rather, the control flow returns fully, and the continuation (the rest of the function) is scheduled to start later. This is a much cleaner solution, because it does not cause re-registration problems, as if you were using DoEvents .
Stephen Cleary Oct 05 2018-11-11T00: 00Z
source share