4

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:

  1. In your “library” async methods, use ConfigureAwait(false) wherever possible.
  2. 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?

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
dyatchenko
  • 2,283
  • 3
  • 22
  • 32

2 Answers2

3

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?

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • Thanks for your elaborated answer. You said that `ConfigureAwait(false)`: 1. saves time 2. avoids deadlocks. And 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? – dyatchenko Mar 01 '15 at 11:55
  • The minus is that you don't return the `SynchronizationContext`, and that would be surprising to the end user. I'll edit my answer to explain. – Yuval Itzchakov Mar 01 '15 at 11:56
  • I read your edit hundred times, but didn't understand exactly what do you mean: `execute a method which returns a Task` where is this method was called? Was it an UI (action method) thread? – dyatchenko Mar 01 '15 at 12:18
  • @dyatchenko I've added an example. Hope that explains what i ment. – Yuval Itzchakov Mar 01 '15 at 12:31
  • Ok. Thanks for your example. Do you mean that we shouldn't update the textbox inside the different context, because it might cause an exception (for WinForms)? – dyatchenko Mar 01 '15 at 13:00
  • @dyatchenko I mean that it feels more natural that you can update your text box after awaiting on a method, just as *you would with synchronous code*. The general purpose of `async-await` is to ease async programming and make it easy for developers to use. – Yuval Itzchakov Mar 01 '15 at 13:03
  • Ok. According to your whole answer, the `ConfigureAwait(false)` is a good practice ONLY for ASP.NET, because of its specific, right? And this is the main reason why Microsoft doesn't encapsulate the `ConfigureAwait(false)` inside the `Task` class. – dyatchenko Mar 01 '15 at 13:07
  • No, that's incorrect. `ConfigureAwait(false)` is recommended anywhere where you don't actually need to marshal the continuation back to the context. It isn't used only in ASP.NET, it can be used anywhere. It is more common to use it in applications that have a synchronization context, such as ASP.NET, WPF and WinForms. – Yuval Itzchakov Mar 01 '15 at 13:09
  • 1
    Yes, you're right, I mean the same thing. Thank you very much! I think I got the answers on my questions. – dyatchenko Mar 01 '15 at 13:14
2

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.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Ok. Got you. Thank you very much Stephen! But why is it impossible to use the async operations inside a constructor of the controller? I've asked about it in the another question: http://stackoverflow.com/questions/28805796/ – dyatchenko Mar 02 '15 at 23:51
  • @dyatchenko: Internally, `DownloadStringTaskAsync` is starting an asynchronous operation in a way very similar to `async void`. – Stephen Cleary Mar 03 '15 at 00:28
  • But why can we use `DownloadTaskAsync` inside the action method without any problems? – dyatchenko Mar 03 '15 at 02:14
  • @dyatchenko: Because the action method (asynchronously) waits for it to complete. The constructor does not. ASP.NET sees that the asynchronous operation is not completed yet, so it throws that exception. – Stephen Cleary Mar 03 '15 at 13:38