I've read here https://blog.stephencleary.com/2009/10/synchronizationcontext-properties.html that ASP.NET applications' execution context does not have specific associated thread. Does it mean code after await will(can) be executed in different thread with the same context ? In this case how it is possible that deadlock can be caused by synchronous execution? Or ASP.NET application is not the case for such deadlock ?
Thanks in advance.
For ASP.NET Classic (.NET Framework), there is a special AspNetSynchronizationContext, the continuation will post back to the original context thread.
ASP.NET Core there isn’t one. If you inspect SynchronizationContext.Current you’ll find that it’s set to null. As such, a continuation is free to use what ever thread it chooses, and will suffer no classic deadlocks in that respect
Update
Some great corrections from #StephenCleary in the comments
Minor correction : on classic ASP.NET, the SynchronizationContext
represents the request context, not a specific thread.
The method may resume on any thread pool thread after the await.
The deadlock occurs because there is a lock as part of that request
context to ensure that only one thread at a time may be in the
request context.
So, when the async method is ready to resume, a thread pool thread
is taken which enters the request context and tries to take that
lock. If there's another thread blocked on that task in the context, the lock is already taken and a deadlock will occur
Related
I read some articles about this question but i need some one clarify this for me,
public async Task<Person> Get()
{
//some code
var result= await AsyncFunction();
return result;
}
about above codes which i understand is when the code execution hit the await the current thread go to thread pool and When the method is ready to continue, any thread may choose from thread pool to continue method execution. is it true or not? the thread before await is same to after 'await' or not?
if i use ConfigureAwait(false) it cause to choose different thread for execution code? or it's not related to thread jump?
I recommend reading my async intro.
When the method is ready to continue, any thread may choose from thread pool to continue method execution. is it true or not? the thread before await is same to after 'await' or not?
In ASP.NET, yes, that is true. Any available thread pool thread may resume execution of that method after the await.
if i use ConfigureAwait(false) it cause to choose different thread for execution code? or it's not related to thread jump?
What actually happens is that the await by default will capture its current "context". On ASP.NET Core, there is no context to capture, so await uses the thread pool context. On ASP.NET pre-Core, there is a SynchronizationContext.Current value that is captured and used to resume executing the method. The ASP.NET (pre-Core) SynchronizationContext may use any thread pool thread; it's just there to ensure some things get copied over, most notably HttpContext.Current.
If you use ConfigureAwait(false), then that is telling the await to not capture the current context. On ASP.NET Core, this has no effect because there's no context to capture anyway. On ASP.NET pre-Core, this will cause the method to resume executing on a thread pool thread but not use the SynchronizationContext, so HttpContext.Current is not available after the await.
I have been trying to understand the concept of context in Task execution in .Net. However, I still am unable to relate context to basic concept of OS threads. While going through this blog, I sort of got the following idea of what a context is:
In GUI applications, there is a single GUI thread which has all the
GUI elements. Now, because one needs to come in the GUI thread to
access the GUI elements, I am assuming the GUI thread has the GUI
elements initialized in its stack space which it doesn't share with
other threads. Therefore, the awaitable needs to schedule the
remainder of the function in the GUI thread if the remainder function
wants to access some GUI element. Similarly, if we talk about HTTP
application which accept HTTP get/post requests, there is a thread
which gets spawned when a request arrives. This thread contains the request context like IP address of the user. Now, if the remainder
function wants to access some HTTP context properties, it has to execute in that thread.
While reading this blog, I came across the idea of context being copied. This has led to me believe the following:
The context of a thread is data members like IP address, GUI elements
etc. When the remainder of a function is scheduled after an awaitable
completes, the remainder may need the context to be present, but not
necessarily on the same thread. So, what is done is any thread is
taken out of the thread pool and the context is copied onto that
thread so that it is accessible. Thereafter, the remainder function is
scheduled on this thread. This can cause a deadlock in the following way. Take GUI
applications for example. At any time, there should be a unique thread
having the GUI context. So, if the GUI thread blocks and doesn't
release the context, the remainder function won't get scheduled.
Can anyone please clarify this for me? What exactly is in a context? And how is the context transferred? Which of the above understanding of mine is right or both are wrong?
UPDATE:
I read this blog and it has a line And this extension method demonstrates how to invoke a function with a specified ExecutionContext (typically, captured from another thread). This is pushing me to believe that my second idea is closer to correctness.
Each context is different. But in general, they're not copied. Contexts are used to schedule Tasks. That is, to find a suitable thread and other resources, as required, and to then execute the task.
In some contexts (GUI), the most important thing is the thread. There's one UI thread, so any Task that a GUI context is asked to schedule has to arrange for the UI thread to execute that Task.
In some contexts (ASP.Net before core), what's important are the "ambient" request/response/session objects. Those objects should only be accessed by a single thread at a time, but any thread can be used. So the context can use thread pool threads but needs to ensure it only executes a single Task at a time.
And in the default context, there's no special thread nor any other special resources. Like the ASP.Net context above, any thread pool thread can be used to execute the Task but it can schedule Tasks as quickly as the thread pool will take them.
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.
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.
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.
Based on the following question:
General purpose FromEvent method
How do I know which thread in my application the event will return?
I can somehow specify which thread will it continue?
What happens to the thread that is using this feature?
These responses appear to be obvious when I use WPF (Dispatcher/Main/UI Thread), but if I'm working with threads MTA, STA, Reactive, ThreadPool (Task/BackgroundWorker), how can I predict what will happen?
Is there any real benefit than using task.Wait() (if I do not have to worry about locking thread)?
How do I know which thread in my application the event will return?
You don't. You never do with events, unless the documentation for a specific event specifies the that it will be executed from the UI thread, a thread pool thread, etc.
I can somehow specify which thread will it continue?
If you want to run code in a UI thread then marshal to the UI thread in the event handler. If you want to run code in a thread pool thread then add a new task to the thread pool inside of the handler. Both of those tasks add overhead if not needed, so it's usually best to look at the documentation of the event to see which is needed.
However, in the case of the linked question, the whole idea is that you're no longer dealing with an event and an event handler, you're dealing with a Task. So if you add a continuation to the task, the question is where will that continuation run? That is entirely specified by you. You can use the default task scheduler and have it run in the thread pool, you can pass a UI SynchronizationContext to run in the UI thread, or you can just let it run wherever the task you are continuing runs. (Meaning you have no idea what thread will be running it.)
If you're using the task with await, then it will automatically configure the continuation to run in the synchronization context you were in before you started that async operation, which may or may not be the UI thread (but likely is). If you specifically don't want that, then use .ConfigureAwait(false);.
Is there any real benefit than using task.Wait() (if I do not have to worry about locking thread)?
The reason to use an asynchronous task based approach is that you're not blocking threads, particularly thread pool threads (since you've specifically said you're not blocking a UI, which is much worse). Having a thread sitting around doing nothing is a problem, in some environments more than others (such as ASP for a highly active site). By not doing a blocking wait, you aren't consuming those resources.
If you await a Task, then there is a "context" that is captured and used to resume the async method. This "context" is the current SynchronizationContext, unless it is null, in which case it's the current TaskScheduler (which these days is usually the thread pool scheduler).
If you're doing async programming, you should be using await and not Wait. Wait can cause deadlocks, as I explain on my blog.
You may also find my async/await intro helpful.
Using the technique you linked to you cannot predict the thread that this runs on. It might be the thread raising the event, but that is not guaranteed (no, really! It isn't. This is a common misbelief).
So you need to force a switch to whatever thread you want to run on. For example use Task.Run to switch to the thread pool or use TaskScheduler.FromCurrentSynchronizationContext to run on the UI.
If you await the task you are guaranteed to resume in the synchronization context that was set before the await. This is probably what you want.
When you have server-side code (i.e. some ApiController) and your functions are asynchronous - so they return Task<SomeObject> - is it considered best practice that any time you await functions that you call ConfigureAwait(false)?
I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context. However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function.
I've typed up an example of what I am talking about below:
public class CustomerController : ApiController
{
public async Task<Customer> Get(int id)
{
// you are on a particular thread here
var customer = await GetCustomerAsync(id).ConfigureAwait(false);
// now you are on a different thread! will that cause problems?
return customer;
}
}
Update: ASP.NET Core does not have a SynchronizationContext. If you are on ASP.NET Core, it does not matter whether you use ConfigureAwait(false) or not.
For ASP.NET "Full" or "Classic" or whatever, the rest of this answer still applies.
Original post (for non-Core ASP.NET):
This video by the ASP.NET team has the best information on using async on ASP.NET.
I had read that it is more performant since it doesn't have to switch thread contexts back to the original thread context.
This is true with UI applications, where there is only one UI thread that you have to "sync" back to.
In ASP.NET, the situation is a bit more complex. When an async method resumes execution, it grabs a thread from the ASP.NET thread pool. If you disable the context capture using ConfigureAwait(false), then the thread just continues executing the method directly. If you do not disable the context capture, then the thread will re-enter the request context and then continue to execute the method.
So ConfigureAwait(false) does not save you a thread jump in ASP.NET; it does save you the re-entering of the request context, but this is normally very fast. ConfigureAwait(false) could be useful if you're trying to do a small amount of parallel processing of a request, but really TPL is a better fit for most of those scenarios.
However, with ASP.NET Web Api, if your request is coming in on one thread, and you await some function and call ConfigureAwait(false) that could potentially put you on a different thread when you are returning the final result of your ApiController function.
Actually, just doing an await can do that. Once your async method hits an await, the method is blocked but the thread returns to the thread pool. When the method is ready to continue, any thread is snatched from the thread pool and used to resume the method.
The only difference ConfigureAwait makes in ASP.NET is whether that thread enters the request context when resuming the method.
I have more background information in my MSDN article on SynchronizationContext and my async intro blog post.
Brief answer to your question: No. You shouldn't call ConfigureAwait(false) at the application level like that.
TL;DR version of the long answer: If you are writing a library where you don't know your consumer and don't need a synchronization context (which you shouldn't in a library I believe), you should always use ConfigureAwait(false). Otherwise, the consumers of your library may face deadlocks by consuming your asynchronous methods in a blocking fashion. This depends on the situation.
Here is a bit more detailed explanation on the importance of ConfigureAwait method (a quote from my blog post):
When you are awaiting on a method with await keyword, compiler
generates bunch of code in behalf of you. One of the purposes of this
action is to handle synchronization with the UI (or main) thread. The key
component of this feature is the SynchronizationContext.Current which
gets the synchronization context for the current thread.
SynchronizationContext.Current is populated depending on the
environment you are in. The GetAwaiter method of Task looks up for
SynchronizationContext.Current. If current synchronization context is
not null, the continuation that gets passed to that awaiter will get
posted back to that synchronization context.
When consuming a method, which uses the new asynchronous language
features, in a blocking fashion, you will end up with a deadlock if
you have an available SynchronizationContext. When you are consuming
such methods in a blocking fashion (waiting on the Task with Wait
method or taking the result directly from the Result property of the
Task), you will block the main thread at the same time. When
eventually the Task completes inside that method in the threadpool, it
is going to invoke the continuation to post back to the main thread
because SynchronizationContext.Current is available and captured. But
there is a problem here: the UI thread is blocked and you have a
deadlock!
Also, here are two great articles for you which are exactly for your question:
The Perfect Recipe to Shoot Yourself in The Foot - Ending up with a Deadlock Using the C# 5.0 Asynchronous Language Features
Asynchronous .NET Client Libraries for Your HTTP API and Awareness of async/await's Bad Effects
Finally, there is a great short video from Lucian Wischik exactly on this topic: Async library methods should consider using Task.ConfigureAwait(false).
The biggest draw back I've found with using ConfigureAwait(false) is that the thread culture is reverted to the system default. If you've configured a culture e.g ...
<system.web>
<globalization culture="en-AU" uiCulture="en-AU" />
...
and you're hosting on a server whose culture is set to en-US, then you will find before ConfigureAwait(false) is called CultureInfo.CurrentCulture will return en-AU and after you will get en-US.
i.e.
// CultureInfo.CurrentCulture ~ {en-AU}
await xxxx.ConfigureAwait(false);
// CultureInfo.CurrentCulture ~ {en-US}
If your application is doing anything which requires culture specific formatting of data, then you'll need to be mindful of this when using ConfigureAwait(false).
I have some general thoughts about the implementation of Task:
Task is disposable yet we are not supposed to use using.
ConfigureAwait was introduced in 4.5. Task was introduced in 4.0.
.NET Threads always used to flow the context (see C# via CLR book) but in the default implementation of Task.ContinueWith they do not b/c it was realised context switch is expensive and it is turned off by default.
The problem is a library developer should not care whether its clients need context flow or not hence it should not decide whether flow the context or not.
[Added later] The fact that there is no authoritative answer and proper reference and we keep fighting on this means someone has not done their job right.
I have got a few posts on the subject but my take - in addition to Tugberk's nice answer - is that you should turn all APIs asynchronous and ideally flow the context . Since you are doing async, you can simply use continuations instead of waiting so no deadlock will be cause since no wait is done in the library and you keep the flowing so the context is preserved (such as HttpContext).
Problem is when a library exposes a synchronous API but uses another asynchronous API - hence you need to use Wait()/Result in your code.