C # ConfigureAwait Task

Thought I was getting a handle on ConfigureAwait , then I tried an experiment.

I understand that ConfigureAwait(false) will only matter if there is a synchronization context.

ASP, WPF, etc. should have a context, but console applications and service applications should not.

To find out how this works, I made a web API application and included the following method:

 // GET api/values/5 public async Task<string> Get (int id) { var syncCtx = SynchronizationContext.Current; int startThreadId = Thread.CurrentThread.ManagedThreadId; await Task.Delay(TimeSpan.FromSeconds(3)).ConfigureAwait(true); int endThreadId = Thread.CurrentThread.ManagedThreadId; return "Start Thread ID: " + startThreadId.ToString() + ": End Thread ID: " + endThreadId.ToString(); } 

My prediction was that without ConfigureAwait or ConfigureAwait set to true , I should see the same thread id before and after the wait.

My first few tests showed that with a true set, as stated above.

Late code runs begin and end on different thread IDs, regardless of ConfigureAwait .

I added syncCtx to convince myself that I have a context.

One caveat I read is that if the task is completed, you will not be guaranteed the same identifier. Is this the case here? If so, why is this so?

Did I install a naive or erroneous test? If so, what would be the right test?

I started this way in a console / service application and realized that I was not getting the same thread id. I added ConfigureAwait(false) , as recommended in most best-practice emails I've seen. Since I like to see how everything works, I tried to check thread ids. Watching them led me to a series of searches that led to the code above.

+6
source share
2 answers

Running ConfigureAwait(true) (or just deleting it, since it is the default) does not start it in the same thread. It tells SynchronizationContext.Current to do a Post or Send with the rest of the sequel. How Post or Send actually runs this code is not defined.

WindowsFormsSynchronizationContext and DispatcherSynchronizationContext (WinForms and WPF contexts) will place the continuation in the message queue processed by Message Pump (UI thread).

On the other hand, the AspNetSynchronizationContext (this is what you are using) simply sets some status information up (for example, setting HttpContext.Current back to its old value), then it pauses the thread thread pool in the next available pool. There is no โ€œMessage Pumpโ€ for ASP.NET, it just does all its work in the thread pool, so it makes no sense to try to get the same thread from the thread pool later, this thread could already be destroyed by the time it continues.

The time when you saw the same identifier before and after you were lucky, and the same thread pulled from the thread pool before and after the continuation.

I highly recommend that you read the MSDN magazine article, โ€œAll About Synchronous Context,โ€ which details how SynchronizationContext works and details about 4 types of contexts built into .NET.

+8
source

SynchronizationContext ! = Thread . If you used something like WPF with your version of Dispatcher , then yes, its SynchronizationContext is bound to one specific thread. However, things like ASP.NET and WCF are not affinity threads, they just carry with them a specific surrounding context that needs to be restored from the thread that they begin to execute next. They can be affine to a specific thread pool, but, again, not to a specific thread.

That is why the SynchronizationContext abstraction was introduced: it allows various structures to determine exactly what affinity means for them, and allows the async / wait infrastructure to work on them completely agnostically.

+6
source

Source: https://habr.com/ru/post/976588/


All Articles