C # 5 Async / Await - is it * simultaneous *?

I was considering new asynchronous stuff in C # 5, and one specific question came up.

I understand that the await keyword is a neat compiler trick / syntax sugar to implement the continuation of the transfer , where the remainder of the method is split into Task objects and queues in the queue, but where control is returned to the calling method.

My problem is that I heard that at the moment it is all in one thread. Does this mean that this asynchronous material is just a way to turn continuation code into Task objects, and then call Application.DoEvents() after each task completes before the next one starts?

Or am I missing something? (This part of the question is rhetorical - I fully understand that something is missing for me :))

Thank you very much in advance.

+52
c # continuations async-await
Oct 05 2018-11-11T00:
source share
4 answers

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 .

+47
Oct 05 2018-11-11T00:
source share

The whole idea of ​​async / await is that it successfully transfers the continuation and does not allocate a new thread for the operation. Continuation can occur in a new stream, it can continue in the same stream.

+5
Oct 05 2018-11-11T00:
source share

The real "meat" (asynchronous) part of async / await is usually done separately, and communication with the caller is done through TaskCompletionSource. As written here http://blogs.msdn.com/b/pfxteam/archive/2009/06/02/9685804.aspx

The TaskCompletionSource type serves two related purposes that its name refers to: it is the source for creating the task and the source for completing these tasks. Essentially, a TaskCompletionSource acts as a producer for the task and its completion.

and the example is clear enough:

 public static Task<T> RunAsync<T>(Func<T> function) { if (function == null) throw new ArgumentNullException("function"); var tcs = new TaskCompletionSource<T>(); ThreadPool.QueueUserWorkItem(_ => { try { T result = function(); tcs.SetResult(result); } catch(Exception exc) { tcs.SetException(exc); } }); return tcs.Task; } 

Through TaskCompletionSource , you have access to the Task object that you can expect, but not through the async / await keywords that you created multithreading.

Note that when many "slow" functions are converted to async / await syntax, you will not need to use TaskCompletionSource very much. They will use it internally (but at the end somewhere there must be a TaskCompletionSource in order to get an asynchronous result)

+2
Oct 05 2018-11-11T00:
source share

The way I would like to explain this is that the β€œwait” keyword just waits for the task to complete, but causes the calling thread to execute while it is waiting. Then it returns the result of the Task and continues execution from the statement after the keyword "wait" after the completion of the task.

Some people I noticed seem to think that the task is running in the same thread as the calling thread, this is incorrect and can be proved if you try to change the Windows.Forms GUI element in a method that is waiting for calls. However, the continuation is performed on the calling thread, where possible.

Its just a neat way to not have callback delegates or event handlers to complete the task.

+1
Nov 03 '11 at 9:52
source share



All Articles