I've been developing some library code that will be consumed by MVC action methods, so I've been reading a lot of Steven Cleary's blogs about the subject.
I ran in to his "Don't Block on Async Code" blog post, but am confused about some parts that seem contradictory.
Under "Preventing the Deadlock" he states:
There are two best practices (both covered in my intro post) that
avoid this situation:
In your “library” async methods, use ConfigureAwait(false) wherever
possible.
Don’t block on Tasks; use async all the way down.
Then later:
Using ConfigureAwait(false) to avoid deadlocks is a dangerous
practice. You would have to use ConfigureAwait(false) for every await
in the transitive closure of all methods called by the blocking code,
including all third- and second-party code. Using
ConfigureAwait(false) to avoid deadlock is at best just a hack).
Given these 2 statements, one saying that ConfigureAwait(false) is a best practice for library code, and one that says it is at best a dangerous hack, what is the actual proper way to write library code that won't deadlock when used in MVC?
I've read other question and answers on SO that might be considered duplicates of this, but none of them seem to address the contradictory information given by one of the experts on async / await.
The information isn't directly contradictory unless you take them out of context:
The former is general advice to writing library code; it's a good idea to do these things to make sure your library behaves well regardless of the synchronization context it's called in.
The latter is explicitly calling out how using ConfigureAwait(false) as a means to avoid a known deadlock scenario is a hack. It's saying,
I want to block here, but doing so would normally cause a deadlock, so I'll push the work to another thread (from the thread-pool) and hope everything works out okay.
If following the earlier advice to not block on tasks (use async all the way down), then this deadlock scenario won't happen.
The deadlock scenario is only relevant when running code within specific synchronization contexts which schedule continuations to execute on the thread which started the task, such as the one used by ASP.NET (a request is processed on one thread) or the one used by Windows desktop applications (a single thread for all UI events).
Blocking on the task in these contexts causes the single thread to block, so the thread is never free to run the continuation and the method deadlocks.
Related
I learnt the hard way that calling Task.Wait from a pool thread can lead to thread-starvation deadlock.
According to this MSDN article, in chapter 'deadlocks', we should obey these two rules:
Do not create any class whose synchronous methods wait for asynchronous functions, since this class could be called from a thread on the pool.
Do not use any class inside an asynchronous function if the class blocks waiting for asynchronous functions.
It seems the only place left for a legitimate use of Task.Wait is the Main function - I am exaggerating a bit here but you get the idea.
Why is Task.Wait still part of the .NET framework, seeing how dangerous it is?
Why is Task.Wait still part of the .NET framework, seeing how
dangerous it is?
Because you want to be able to synchronously block on a Task. Rarely, but you still do. As you said, Main is probably the most popular (and preferably the only) place where that would happen. That, and the fact that Microsoft is notorious for it's backwards compatability, so once this was introduced, it is highly unlikely to be deprecated or disappear from the BCL. Same goes for Task.WaitAll.
The real problem IMO starts when people don't properly read the documentation and don't understand the implications of calling such a method and end up misusing it. If you use it carefully, it does it's job great.
Another thing is the fact that you can't always go async all the way. Unfortunately, many times you have code, which is synchronous by signature, which can't be altered and needs to invoke an async method call. Yes, this is dangerous and discouraged by all and is considered an anti-pattern with async code, and I myself have answered at least a dozen question on SO where people end up deadlocking themselves and don't understand why, but the TPL authors still needed to make these type of calls possible.
I have been applying async best practices to all my libraries. Basically it means:
Only use async when it's truly async (libraries shouldn't lie)
Define a synchronous method if and only if you have a faster synchronous method that won’t dead lock.
Postfix all async methods with Async
I worked on a library that is synchronous by nature. This means it has only sync methods. If the user wants to run the work on a separate thread than the UI thread, they can do that themselves by using Task.Factory (responsibility of the caller).
However, inside a handler / method / extensibility point, we want to show the user a message box. This is an async method (for example, WinRT ShowDialogAsync). Then this gives us the following options:
A. Move everything to async (so we have the option to use await in our handlers and don't block anything).
public async Task MyMethodAsync()
{
await _messageService.ShowAsync();
}
The advantage is that users can add async methods without having to use .Wait(). The downside is that we are lying as a library (it's not truly async).
I have considered making everything async, but I don't think that's a good idea either. It would make all libraries lie but prepare them in case we would need it. Remember that making everything async out of the box has a (small) performance impact as well.
B. Inside the handler that requires user input, call .Wait()
public void MyMethod()
{
_messageService.ShowAsync().Wait();
}
The advantage is that this will allow us to use async code inside sync methods. But... it will never be callable from the UI-thread because the _messageService dispatches to the UI thread (but it cannot do that because it's still waiting for the method, resulting in a deadlock). This method will work when used inside a Task.Factory.Run block (but the responsibility is up to the end-user):
await Task.Factory.Run(() => MyMethod());
The question
I feel that both have pros and cons, but what would you choose? Let the library lie (A) or only allow the method to be called from a background thread (B)? Or maybe there are other options I've overseen.
If I go for A, it means I have to bump the major version every time (because it's actually a breaking change) whenever a user requests to convert a method to an async signature method.
Define a synchronous method if and only if you have a faster synchronous method that won’t dead lock.
I'd say "define a synchronous method if you have synchronous work to do". It doesn't matter how fast it is. The burden is on the caller to determine if it's too slow and they need to use Task.Run.
However, inside a handler / method / extensibility point
If this is an Observer kind of extensibility, consider just using events or observables.
However, it sounds like you want more of a Strategy kind of extensibility, where your invoking code must wait for and/or change its behavior based on the result of the callback.
I have considered making everything async, but I don't think that's a good idea either.
Async all the way is a guideline, not a strict command. It definitely applies in the 99% case, but this could be one of the exceptions. I would try not to make a library async just for the sake of a possibly-async Strategy pattern; I'd investigate other extension possibilities first. There is a valid argument for making the library async, if you view the Strategy callback as a dependency (the library would be async because its dependency is (possibly) async).
As you've discovered, there's no clean way to do sync-over-async. There are a few different hacks (such as blocking from a background thread), but you'll first need to decide whether you need to call your library from the UI thread.
If you do, then there's just two options: make the library async, or use a nested message loop. I strongly avoid nested message loops, especially in libraries; I'm just mentioning it for sake of completeness.
If you can impose on the user a requirement to only call the library from a non-UI thread, then you can apply other hacks. E.g., blocking the background thread.
There's not an easy solution, sorry.
As far as me personally... if the library needs an async Strategy, then I would lean towards making the library async. But it does depend on what kind of library it is, whether there were backwards-compatibility issues, etc. And the first thing I'd look into is a different kind of extensibility point.
as you can read here :
https://msdn.microsoft.com/en-us/magazine/jj991977.aspx
Async All the Way
Asynchronous code reminds me of the story of a fellow who mentioned that the world was suspended in space and was immediately challenged by an elderly lady claiming that the world rested on the back of a giant turtle. When the man enquired what the turtle was standing on, the lady replied, “You’re very clever, young man, but it’s turtles all the way down!” As you convert synchronous code to asynchronous code, you’ll find that it works best if asynchronous code calls and is called by other asynchronous code—all the way down (or “up,” if you prefer). Others have also noticed the spreading behavior of asynchronous programming and have called it “contagious” or compared it to a zombie virus. Whether turtles or zombies, it’s definitely true that asynchronous code tends to drive surrounding code to also be asynchronous. This behavior is inherent in all types of asynchronous programming, not just the new async/await keywords.
“Async all the way” means that you shouldn’t mix synchronous and asynchronous code without carefully considering the consequences. In particular, it’s usually a bad idea to block on async code by calling Task.Wait or Task.Result. This is an especially common problem for programmers who are “dipping their toes” into asynchronous programming, converting just a small part of their application and wrapping it in a synchronous API so the rest of the application is isolated from the changes. Unfortunately, they run into problems with deadlocks. After answering many async-related questions on the MSDN forums, Stack Overflow and e-mail, I can say this is by far the most-asked question by async newcomers once they learn the basics: “Why does my partially async code deadlock?”
According to this article ASP.NET requires using the same SynchronizationContext for asynchronous operations in the controller, otherwise it blocks the running thread. As a conclusion author mentioned that we should use both the methods as the best practice to prevent threads deadlocks:
In your “library” async methods, use ConfigureAwait(false) wherever possible.
Don’t block on Tasks; use async all the way down.
Note: It is best to apply both best practices. Either one will prevent
the deadlock, but both must be applied to achieve maximum performance and responsiveness.
But what purpose led Microsoft to use the same SynchronizationContext? May be using of the ConfigureAwait(false), which disables the same sync context restriction, might lead to e.g. unpredictable behavior or performance issues. Thus, is it really good practice to use the ConfigureAwait(false) wherever is possible?
ASP.NET requires using the same SynchronizationContext for
asynchronous operations in the controller, otherwise it blocks the
running thread.
I'm not really sure what that statement means. ASP.NET doesn't require "the same" synchronization context. In order for you to be inside your HttpContext, you need that SynchronizationContext.
But what purpose led Microsoft to use the same SynchronizationContext?
I suggest you read It's All About SynchronizationContext to get the bigger picture about sync contexts. Basically, it's a mechanism which allows you to post continuations on a particular thread. It can be used, for example, to marshal work back onto the UI message loop thread inside UI applications.
May be using of the ConfigureAwait(false), which disables the same
sync context restriction, might lead to e.g. unpredictable behavior or
performance issues
On the contrary. Marshaling work back onto the sync context does have (very minimal) overhead, as the request needs to be posted (using the abstract SynchronizationContext.Post) back onto the desired thread and context. By using ConfigureAwait(false), you're saving that time and simply continuing execution on which ever thread was allocated.
Thus, is it really good practice to use the ConfigureAwait(false)
wherever is possible?
The primary reason to do that is to avoid deadlocks. When someone calling Task.Result or Task.Wait instead of asynchronously waiting using await, you get the classic deadlock scenario where the sync context is attempting to post the continuation back onto the thread, but it is currently blocked because Result and Wait are blocking calls. The other reason is the minor performance overhead you get.
Edit:
Why doesn't Microsoft encapsulate this method inside the Task class?
It looks like the ConfigureAwait(false) has just only the pluses. Is
there any minuses?
Let's image the following scenario: You execute a method which returns a Task and is awaited using await, and right after that you update some UI element. Now, what would be more natural to you? Would you prefer to implicitly return to the same "environment" you were before (the UI thread), or would you prefer that you had to explicitly specify that you want to return to that same environment?
I think that the former "feels" more natural to the user.
Example:
public Task FetchAndReturnAsync(string url)
{
var httpClient = new HttpClient();
return httpClient.GetAsync(url);
}
You call it like this:
var awesomeUiResult = await FetchAndReturnAsync("http://www.google.com");
textBox.Text = awesomeUiResult;
What do you think should happen? Is it more natural for you to be able to update the text box after the await, or for it to fail because you're now not inside your original context?
ASP.NET requires using the same SynchronizationContext for asynchronous operations in the controller, otherwise it blocks the running thread.
Sort of, but not quite. ASP.NET creates a SynchronizationContext for each incoming request, and this context is not tied to a specific thread at all. However, only one thread at a time can enter the context, so if a second thread attempts to enter it while one is already in it, then it will block that thread.
what purpose led Microsoft to use the same SynchronizationContext?
The SynchronizationContext for ASP.NET manages per-request data such as HttpContext.Current, culture, and user identity.
is it really good practice to use the ConfigureAwait(false) wherever is possible?
As a general rule, yes, especially for generic libraries. On ASP.NET, ConfigureAwait(false) doesn't gain you much - in some cases, a minor performance increase. It can be used to avoid the deadlock I mention in my article, but it's far better (especially on ASP.NET) to use async all the way.
For example a scenario in Winform where the UI thread will be blocked while we use
HttpWebRequest synchronously which in turn requests resources on Internet. Here we can use async method to execute the method while await keyword for certain task allows user to interact with winform even though the request is still running.
This can even be achieved by delegation so what's the advantage of Async Feature?
One of the nicest advantages in my opinion is a more concise way to understand the async programming pattern with less lines of code. If you want to see more clearly how it works, check out this question answered by Jon Skeet: How does Task<int> become a int?
The async and await termonoligy is much simpler and you can basicaly write your code just as you would do a syncronious application by just adding some keywords.
From MSDN:
You can avoid performance bottlenecks and enhance the overall
responsiveness of your application by using asynchronous programming.
However, traditional techniques for writing asynchronous applications
can be complicated, making them difficult to write, debug, and
maintain.
Visual Studio 2012 introduces a simplified approach, async
programming, that leverages asynchronous support in the .NET Framework
4.5 and the Windows Runtime. The compiler does the difficult work that the developer used to do, and your application retains a logical
structure that resembles synchronous code. As a result, you get all
the advantages of asynchronous programming with a fraction of the
effort.
http://msdn.microsoft.com/en-us/library/vstudio/hh191443.aspx
I assume by "delegation" you mean to call the synchronous methods from a background thread.
As others have pointed out, the code is easier to read and write using async and await, but there's another important difference as well.
When you use synchronous methods, the calling thread is blocked until the operation is complete.
When you use synchronous methods from a background thread, the UI thread is not blocked but the background thread still is.
When you use asynchronous methods, no threads are blocked. This allows more efficient usage of your resources, with less pressure on the thread pool.
I'm currently working on a largely asynchronous application which uses TAP throughout. Every class which has methods for spawning Tasks also has a TaskScheduler injected into it. This allows us to perform explicit scheduling of tasks, which as I understand, is not the way Microsoft are going with the Async CTP.
The only issue I have with the new approach (implicit scheduling) is that our previous philosophy has always been "we know the continuation will always specify their task scheduler, so we don't need to worry about what context we complete the task on".
Moving away from that does worry us slightly just because it has worked extremely well in terms of avoiding subtle threading errors, because for every bit of code we can see that the coder has remembered to consider what thread he's on. If they missed specifying the task scheduler, it's a bug.
Question 1: Can anyone reassure me that the implicit approach is a good idea? I see so many issues being introduced by ConfigureAwait(false) and explicit scheduling in legacy/third party code. How can I be sure my 'await-ridden' code is always running on the UI thread, for example?
Question 2: So, assuming we remove all TaskScheduler DI from our code and begin to use implicit scheduling, how do we then set the default task scheduler? What about changing scheduler midway through a method, just before awaiting an expensive method, and then setting it back again afterward?
(p.s. I have already read http://msmvps.com/blogs/jon_skeet/archive/2010/11/02/configuring-waiting.aspx)
I'll take a shot at answering. ;)
Question 1: Can anyone reassure me that the implicit approach is a good idea? I see so many issues being introduced by ConfigureAwait(false) and explicit scheduling in legacy/third party code. How can I be sure my 'await-ridden' code is always running on the UI thread, for example?
The rules for ConfigureAwait(false) are pretty simple: use it if the rest of your method can be run on the threadpool, and don't use it if the rest of your method must run in a given context (e.g., UI context).
Generally speaking, ConfigureAwait(false) should be used by library code, and not by UI-layer code (including UI-type layers such as ViewModels in MVVM). If the method is partially-background-computation and partially-UI-updates, then it should be split into two methods.
Question 2: So, assuming we remove all TaskScheduler DI from our code and begin to use implicit scheduling, how do we then set the default task scheduler?
async/await does not normally use TaskScheduler; they use a "scheduling context" concept. This is actually SynchronizationContext.Current, and falls back to TaskScheduler.Current only if there is no SynchronizationContext. Substituting your own scheduler can therefore be done using SynchronizationContext.SetSynchronizationContext. You can read more about SynchronizationContext in this MSDN article on the subject.
The default scheduling context should be what you need almost all of the time, which means you don't need to mess with it. I only change it when doing unit tests, or for Console programs / Win32 services.
What about changing scheduler midway through a method, just before awaiting an expensive method, and then setting it back again afterward?
If you want to do an expensive operation (presumably on the threadpool), then await the result of TaskEx.Run.
If you want to change the scheduler for other reasons (e.g., concurrency), then await the result of TaskFactory.StartNew.
In both of these cases, the method (or delegate) is run on the other scheduler, and then the rest of the method resumes in its regular context.
Ideally, you want each async method to exist within a single execution context. If there are different parts of the method that need different contexts, then split them up into different methods. The only exception to this rule is ConfigureAwait(false), which allows a method to start on an arbitrary context and then revert to the threadpool context for the remainder of its execution. ConfigureAwait(false) should be considered an optimization (that's on by default for library code), not as a design philosophy.
Here's some points from my "Thread is Dead" talk that I think may help you with your design:
Follow the Task-Based Asynchronous Pattern guidelines.
As your code base becomes more asynchronous, it will become more functional in nature (as opposed to traditionally object-oriented). This is normal and should be embraced.
As your code base becomes more asynchronous, shared-memory concurrency gradually evolves to message-passing concurrency (i.e., ConcurrentExclusiveSchedulerPair is the new ReaderWriterLock).