Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Task ConfigureAwait

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

My understanding is that ConfigureAwait(false) will only make a difference if there is a synchronization context.

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

To see how it works I made a Web API app 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 with no ConfigureAwait or ConfigureAwait set to true, I should see the same thread ID before and after the await.

My first few tests showed exactly that with the true set as above.

Later runs of the code started and ended on different thread ids regardless of ConfigureAwait.

I added syncCtx to convince myself I have a context.

The one caveat I have read is that if the task has completed, you won't be guaranteed the same ID. Is that the case here? If so, why is that the case?

Have I set up a naive or flawed test? If so, what would be a proper test?

I started down this path in a console/service app and realized I was not getting the same thread ID. I was adding ConfigureAwait(false) as recommended in most "best practice" write ups I have seen. Since I like to see how things really work, I tried testing the Thread IDs. Seeing them differ led me through a number of searches that resulted in the above code.

like image 530
jeffa00 Avatar asked Oct 10 '14 21:10

jeffa00


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.

Is C language easy?

Compared to other languages—like Java, PHP, or C#—C is a relatively simple language to learn for anyone just starting to learn computer programming because of its limited number of keywords.

What is C full form?

Originally Answered: What is the full form of C ? C - Compiler . C is a general-purpose, high-level language that was originally developed by Dennis M. Ritchie to develop the UNIX operating system at Bell Labs. C was originally first implemented on the DEC PDP-11 computer in 1972.


2 Answers

Doing ConfigureAwait(true) (or just leaving it off, as it is the default value) does not make it run on the same thread. It tells SynchronizationContext.Current to do a Post or Send with the rest of the continueation. How Post or Send actually runs that code is not defined.

WindowsFormsSynchronizationContext and DispatcherSynchronizationContext (WinForms and WPF's contexts) both will put the continuation on to the queue of messages to be processed by the Message Pump (the UI thread).

On the other hand, AspNetSynchronizationContext (which is what you are running under) just sets some state information up (like setting HttpContext.Current back to its old value), it then queues the work on the next available thread pool thread. There is no "Message Pump" for ASP.NET, it just does all of its work on the thread pool, so there is no point in trying to get the same thread out of the thread pool at a later time, that thread may already been destroyed by the time the continuation happens.

The times you saw the same ID before and after you just got lucky and the same thread got pulled out of the thread pool before and after the continuation.

I highly recommend you read the MSDN magazine article "It's All About the SynchronizationContext", it goes in to detail explaining how the SynchronizationContext works and goes in to a little detail about the 4 types of contexts built in to .NET.

like image 77
Scott Chamberlain Avatar answered Oct 04 '22 00:10

Scott Chamberlain


SynchronizationContext != Thread. If you were using something like WPF with its Dispatcher runtime then, yes, its SynchronizationContext happens to be tied to one specific thread. However things like ASP.NET and WCF are not thread affine, they just carry along with them specific ambient context that needs to be restored on whatever thread they begin executing on next. They may be affine to a specific thread pool, but, again, not a specific thread.

This is precisely why the SynchronizationContext abstraction was introduced: it allows different frameworks to decide exactly what affinity means to them and allows the async/await infrastructure to work on top of them in a totally agnostic way.

like image 28
Drew Marsh Avatar answered Oct 03 '22 23:10

Drew Marsh