Set SynchronizationContext to null instead of using ConfigureAwait(false) - c#

I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method. I can't control that async method (it uses async/await and does not use ConfigureAwait(false)), nor can I replace it.
The code executes in the context of an ASP .NET request, so to avoid deadlocks, here's what I've done:
var capturedContext = SynchronizationContext.Current;
try
{
// Wipe the sync context, so that the bad library code won't find it
// That way, we avoid the deadlock
SynchronizationContext.SetSynchronizationContext(null);
// Call the async method and wait for the result
var task = MyMethodAsync();
task.Wait();
// Return the result
return task.Result;
}
finally
{
// Restore the sync context
SynchronizationContext.SetSynchronizationContext(capturedContext);
}
Does this produce the same effect as if MyMethodAsync had used ConfigureAwait(false) on all of its await's? Are there some other problems with this approach that I'm overlooking?
(MyMethodAsync is completely unaware that it's being run in an ASP .NET context, it doesn't do any calls to HttpContext.Current or anything like that. It just does some async SQL calls, and the writer didn't put ConfigureAwait(false) on any of them)

I have a library that exposes synchronous and asynchronous versions of a method, but under the hood, they both have to call an async method.
The library is wrong to expose a synchronous version. Just pretend the synchronous API doesn't exist.
so to avoid deadlocks
There shouldn't be any problems with deadlocks if you call an asynchronous method that uses async/await. If it doesn't use ConfigureAwait(false), then it's not as efficient as it could be, that's all. Deadlocks due to ConfigureAwait(false) only apply when you're trying to do sync-over-async (i.e., if you're calling the synchronous APIs from that library).
So, the easiest and simplest solution is to just ignore the synchronous APIs, which are incorrectly designed anyway:
return await MyMethodAsync();

Provided you wrap this technique in a suitably named static function, I think your suggest is significantly better than Task.Run, even if still the lesser of two evils.
Task.Run has a number of issues:
It is not clear why you are using it, you want to start a new task on a web server? This will be deleted by new developers fast if there are no comments. And then boom, difficult to diagnose production issues (deadlocks).
It starts on a new thread pool thread when it doesn't need to until it reaches its first await completed continuation.
It makes you block synchronously for the entire Task returning function, when from your description of the problem, the blocking is actually just part of the overall task. What is being encouraged here is longer blocking over async code, this is certainly not what you want.
If you use it multiple levels, you are multiplying the problem (with SetSynchronizationContext there's no harm in doing it more than once).
If it turns out that there was no blocking / deadlock where you thought there was, or it had been fixed, Task.Run now is introducing blocking over async, whereas SetSynchronizationContext will not cost you anything, in addition to the optimizations it makes by not resuming on the context constantly.
I also understand there is hesitance to make any recommendation given blocking on async code should be avoided at all costs, however you have made it clear you are aware of this and this is to fix a known case of this outside of your immediate control. I think the dogmatic attitude towards this topic is damaging to the .NET ecosystem.

Setting the SynchronizationContext to null seems hacky for me. Instead you can really delegate the work to threadpool. Use Task.Run..
var result = Task.Run(() => MyMethodAsync()).Result;
or
var result = Task.Run(async () => await MyMethodAsync()).Result;
This avoids the deadlock and eliminates the hacky code as well.

Related

release the calling thread while calling async function in synchronous context

It seems it is impossible in c# (dotnet core 3.1) to call an asynchronous function from a non-async method without blocking the original thread. Why ?
Code example:
public async Task myMethodAsync() {
await Task.Delay(5000);
}
public void callingMethhod() {
myMethodAsync().Wait(); // all flavours of this expression, like f.ex. .Result seem to be blocking the calling thread
}
What is the technical limitation for being able to release the calling thread until the async method completes, and then continue execution from there? Is it something technically impossible?
Yes, that is expected. That is why the concept of Task etc exist. If it was possible to do what you want: they wouldn't need to - we could just wave a wand and everything would be async. The entire point of awaitable types is that releasing the calling thread while allowing later continuation is hard, and requires coordination and participation from the calling code; and from what ever calls that; etc - all the way up the stack to whatever is running the threads. Your callingMethhod code is synchronous: it has only a few things it can do:
it can run to completion - meaning: it would have to block
it can throw an exception
The impact of this is that async/await is infectious; anything that touches awaitables kinda needs to also be awaitable, which means: you would typically only call myMethodAsync from a callingMethhod that returned a [Value]Task[<T>], and which is presumably async with an await (although those bits aren't strictly necessary in the example shown).
It seems it is impossible in c# (dotnet core 3.1) to call an asynchronous function from a non-async method without blocking the original thread. Why ?
Because that's what synchronous means. Synchronous means it blocks the thread until the method is complete.
What is the technical limitation for being able to release the calling thread until the async method completes, and then continue execution from there? Is it something technically impossible?
If your calling method wants to release its thread, then make it asynchronous. Asynchronous methods are capable of releasing their calling threads. There's nothing impossible here; it's been solved by async and await.
Now, if you're asking "why can't every method implicitly be async", then that is in theory possible, but it causes a couple of major issues. It can never be done in C# for backwards compatibility reasons. The two issues that immediately come to mind are:
Limited interop. It's not possible to use an "everything is async" language to interop with anything that uses old-school threading (Win32 mutexes, et. al.).
Unexpected concurrency. There are a lot of scenarios where developers make an assumption of synchronous code. If every method is potentially asynchronous, then even code as simple as var x = this._list[0]; this._list.RemoveAt(0); is no longer safe.

C# Async await deadlock problem gone in .NetCore?

In .NetFramework there was a high risk of a deadlock occuring when synchronizing to the synchronization context using:
var result = asyncMethod().Result;
var result = asyncMethod().GetAwaiter().GetResult();
instead of
var result = await asyncMethod();
(read Stephen Cleary blogpost for more info)
Since the synchronization context has been removed in .NetCore. Does this mean that the above methods are now safe to use?
Yes and no. It's true that there's no synchronization context in .NET Core, and thereby, one of the major sources of deadlock issues has been eliminated. However, this doesn't mean that deadlocks are totally impossible. Regardless, you should not let good programming practices slide, just because it may not be a big issue in one circumstance any more. ASP.NET Core, in particular, is fully async, so there is no reason to ever use a sync version of a method or simply block on an async task. Use await as you always would and should.
You Can Block on Async Code - But You Shouldn’t
The first and most obvious consequence is that there’s no context captured by await. This means that blocking on asynchronous code won’t cause a deadlock. You can use Task.GetAwaiter().GetResult() (or Task.Wait or Task.Result) without fear of deadlock.
However, you shouldn’t. Because the moment you block on asynchronous code, you’re giving up every benefit of asynchronous code in the first place. The enhanced scalability of asynchronous handlers is nullified as soon as you block a thread.
There were a couple of scenarios in (legacy) ASP.NET where blocking was unfortunately necessary: ASP.NET MVC filters and child actions. However, in ASP.NET Core, the entire pipeline is fully asynchronous; both filters and view components execute asynchronously.
In conclusion, ideally you should strive to use async all the way; but if your code needs to, it can block without danger.
-Extract from blogpost by Stephen Cleary
Credit to GSerg for finding the post
However, you might encounter thread pool starvation
http://labs.criteo.com/2018/10/net-threadpool-starvation-and-how-queuing-makes-it-worse/

Async-Await no deadlock where a deadlock is expected

It is known that synchronous waiting on an async method leads to deadlocks
(see, for example Don't Block on Async Code)
I have the following code in an event handler for a button-click in a Windows Forms application (i.e. the code is invoked with a UI SynchronizationContext installed).
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.com"));
Task<HttpResponseMessage> t = client.SendAsync(request);
t.Wait();
var response = t.Result;
I fully expected the code to deadlock on clicking the button. However, what I actually see is synchronous waiting - the dialog becomes unresponsive for a while, and then accepts events as usual.
I consistently see deadlocks when I try to synchronously wait on client async methods. However, synchronously waiting on library async methods like SendAsync or ReadAsByteArrayAsync seems not to deadlock. Can someone explain this behaviour?
Don't implementations of async methods in .NET libraries use await statements internally, so that the continuations have to be marshalled back to the original SynchronizationContext?
Note:
If I define a client method, say
public async Task<byte[]> wrapperMethod()
{
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, new Uri("http://www.google.com"));
var response = await client.SendAsync(request);
return await response.Content.ReadAsByteArrayAsync();
}
and then say byte[] byteArray = wrapperMethod().Result; in the button click handler, I do obtain a deadlock.
Don't implementations of async methods in .NET libraries use await statements internally?
Generally, no. I have yet to see a single implementation in the .NET framework that uses async-await internally. It does use tasks and continuations but not the compiler magic the async and await keywords bring.
Using async-await is simple as the code looks synchronous but actually runs asynchronously. But that simplicity has a very small price in performance.
For most consumers this prices is worth paying, but the framework itself tries to be as performant as possible.
However, synchronously waiting on library async methods like SendAsync or ReadAsByteArrayAsync seems not to deadlock.
The deadlock is a result of the default behaviour of await. When you await an uncompleted task the SynchronizationContext is captured and when it's completed the continuation is resumed on that SynchronizationContext (if it exists). When there's no async, await, captured SynchronizationContext, etc. this kind of deadlock can't happen.
HttpClient.SendAsync specifically uses TaskCompletionSource to return a task without marking the method as async. You can see that in the implementation on github here.
Most task-returning methods added to existing classes for async-await simply build a task using the already existing asynchronous API (i.e. BeginXXX/EndXXX). For example this is TcpClient.ConnectAsync:
public Task ConnectAsync(IPAddress address, int port)
{
return Task.Factory.FromAsync(BeginConnect, EndConnect, address, port, null);
}
When you do use async-await though you avoid the deadlock by using ConfigureAwait(false) when you don't need to capture the SynchronizationContext. It's recommended that libraries should alway use it unless the context is needed (e.g. a UI library).
You won't cause a deadlock by blocking on most out-of-the box Task-returning .NET calls because they wouldn't internally touch the SynchronizationContext that the Task was started on unless absolutely necessary (two reasons: performance and avoiding deadlocks).
What this means is that even if standard .NET calls did use async/await under the covers (i3arnon said they don't - I won't argue as I simply don't know), they would, beyond any doubt, use ConfigureAwait(false) unless capturing the context is definitely required.
But that's the .NET framework. As for your own code, you will observe a deadlock if you call wrapperMethod().Wait() (or Result) in your client (provided that you're running with a non-null SynchronizationContext.Current - if you're using Windows Forms, this will definitely be the case). Why? Because you're flaunting async/await best practices by not using ConfigureAwait(false) on your awaitables inside async methods that do not interact with the UI, causing the state machine to generate continuations that unnecessarily execute on the original SynchronizationContext.

ConfigureAwait(false) on Top Level Requests

I'm trying to figure out if ConfigureAwait(false) should be used on top level requests. Reading this post from a somewhat authority of the subject:
http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
...he recommends something like this:
public async Task<JsonResult> MyControllerAction(...)
{
try
{
var report = await _adapter.GetReportAsync();
return Json(report, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json("myerror", JsonRequestBehavior.AllowGet); // really slow without configure await
}
}
public async Task<TodaysActivityRawSummary> GetReportAsync()
{
var data = await GetData().ConfigureAwait(false);
return data
}
...it says to using ConfigureAwait(false) on every await except the top level call. However when doing this my exception takes several seconds to return to the caller vs. using it and it and having it come back right away.
What is the best practice for MVC controller actions that call async methods? Should I use ConfigureAwait in the controller itself or just in the service calls that use awaits to request data, etc.? If I don't use it on the top level call, waiting several seconds for the exception seems problematic. I don't need the HttpContext and I've seen other posts that said always use ConfigureAwait(false) if you don't need the context.
Update:
I was missing ConfigureAwait(false) somewhere in my chain of calls which was causing the exception to not be returned right away. However the question still remains as posted as to whether or not ConfigureAwait(false) should be used at the top level.
Is it a high traffic website? One possible explanation might be that you're experiencing ThreadPoolstarvation when you are not using ConfigureAwait(false). Without ConfigureAwait(false), the await continuation is queued via AspNetSynchronizationContext.Post, which implementation boils down to this:
Task newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action));
_lastScheduledTask = newTask; // the newly-created task is now the last one
Here, ContinueWith is used without TaskContinuationOptions.ExecuteSynchronously (I'd speculate, to make continuations truly asynchronous and reduce a chance for low stack conditions). Thus, it acquires a vacant thread from ThreadPool to execute the continuation on. In theory, it might happen to be the same thread where the antecedent task for await has finished, but most likely it'd be a different thread.
At this point, if ASP.NET thread pool is starving (or has to grow to accommodate a new thread request), you might be experiencing a delay. It's worth mentioned that the thread pool consists of two sub-pools: IOCP threads and worker threads (check this and this for some extra details). Your GetReportAsync operations is likely to complete on an IOCP thread sub-pool, which doesn't seem to be starving. OTOH, the ContinueWith continuation runs on a worker thread sub-pool, which appears to be starving in your case.
This is not going to happen in case ConfigureAwait(false) is used all the way through. In that case, all await continuations will run synchronously on the same threads the corresponding antecedent tasks have ended, be it either IOCP or worker threads.
You can compare the thread usage for both scenarios, with and without ConfigureAwait(false). I'd expect this number to be larger when ConfigureAwait(false) isn't used:
catch (Exception ex)
{
Log("Total number of threads in use={0}",
Process.GetCurrentProcess().Threads.Count);
return Json("myerror", JsonRequestBehavior.AllowGet); // really slow without configure await
}
You can also try increasing the size of the ASP.NET thread pool (for diagnostics purpose, rather than an ultimate solution), to see if the described scenario is indeed the case here:
<configuration>
<system.web>
<applicationPool
maxConcurrentRequestsPerCPU="6000"
maxConcurrentThreadsPerCPU="0"
requestQueueLimit="6000" />
</system.web>
</configuration>
Updated to address the comments:
I realized I was missing a ContinueAwait somewhere in my chain. Now it
works fine when throwing an exception even when the top level doesn't
use ConfigureAwait(false).
This suggests that your code or a 3rd party library in use might be using blocking constructs (Task.Result, Task.Wait, WaitHandle.WaitOne, perhaps with some added timeout logic). Have you looked for those? Try the Task.Run suggestion from the bottom of this update. Besides, I'd still do the thread count diagnostics to rule out thread pool starvation/stuttering.
So are you saying that if I DO use ContinueAwait even at the top level
I lose the whole benefit of the async?
No, I'm not saying that. The whole point of async is to avoid blocking threads while waiting for something, and that goal is achieved regardless of the added value of ContinueAwait(false).
What I'm saying is that not using ConfigureAwait(false) might introduce redundant context switching (what usually means thread switching), which might be a problem in ASP.NET if thread pool is working at its capacity. Nevertheless, a redundant thread switch is still better than a blocked thread, in terms of the server scalability.
In all fairness, using ContinueAwait(false) might also cause redundant context switching, especially if it's used inconsistently across the chain of calls.
That said, ContinueAwait(false) is also often misused as a remedy against deadlocks caused by blocking on asynchronous code. That's why I suggested above to look for those blocking construct across all code base.
However the question still remains as posted as to whether or not
ConfigureAwait(false) should be used at the top level.
I hope Stephen Cleary could elaborate better on this, by here's my thoughts.
There's always some "super-top level" code that invokes your top-level code. E.g., in case of a UI app, it's the framework code which invokes an async void event handler. In case of ASP.NET, it's the asynchronous controller's BeginExecute. It is the responsibility of that super-top level code to make sure that, once your async task has completed, the continuations (if any) run on the correct synchronization context. It is not the responsibility of the code of your task. E.g., there might be no continuations at all, like with a fire-and-forget async void event handler; why would you care to restore the context inside such handler?
Thus, inside your top-level methods, if you don't care about the context for await continuations, do use ConfigureAwait(false) as soon as you can.
Moreover, if you're using a 3rd party library which is known to be context agnostic but still might be using ConfigureAwait(false) inconsistently, you may want to wrap the call with Task.Run or something like WithNoContext. You'd do that to get the chain of the async calls off the context, in advance:
var report = await Task.Run(() =>
_adapter.GetReportAsync()).ConfigureAwait(false);
return Json(report, JsonRequestBehavior.AllowGet);
This would introduce one extra thread switch, but might save you a lot more of those if ConfigureAwait(false) is used inconsistently inside GetReportAsync or any of its child calls. It'd also serve as a workaround for potential deadlocks caused by those blocking constructs inside the call chain (if any).
Note however, in ASP.NET HttpContext.Current is not the only static property which is flowed with AspNetSynchronizationContext. E.g., there's also Thread.CurrentThread.CurrentCulture. Make sure you really don't care about loosing the context.
Updated to address the comment:
For brownie points, maybe you can explain the effects of
ConfigureAwait(false)... What context isn't preserved.. Is it just the
HttpContext or the local variables of the class object, etc.?
All local variables of an async method are preserved across await, as well as the implicit this reference - by design. They actually gets captured into a compiler-generated async state machine structure, so technically they don't reside on the current thread's stack. In a way, it's similar to how a C# delegate captures local variables. In fact, an await continuation callback is itself a delegate passed to ICriticalNotifyCompletion.UnsafeOnCompleted (implemented by the object being awaited; for Task, it's TaskAwaiter; with ConfigureAwait, it's ConfiguredTaskAwaitable).
OTOH, most of the global state (static/TLS variables, static class properties) is not automatically flowed across awaits. What does get flowed depends on a particular synchronization context. In the absence of one (or when ConfigureAwait(false) is used), the only global state preserved with is what gets flowed by ExecutionContext. Microsoft's Stephen Toub has a great post on that: "ExecutionContext vs SynchronizationContext". He mentions SecurityContext and Thread.CurrentPrincipal, which is crucial for security. Other than that, I'm not aware of any officially documented and complete list of global state properties flowed by ExecutionContext.
You could peek into ExecutionContext.Capture source to learn more about what exactly gets flowed, but you shouldn't depend on this specific implementation. Instead, you can always create your own global state flow logic, using something like Stephen Cleary's AsyncLocal (or .NET 4.6 AsyncLocal<T>).
Or, to take it to the extreme, you could also ditch ContinueAwait altogether and create a custom awaiter, e.g. like this ContinueOnScope. That would allow to have precise control over what thread/context to continue on and what state to flow.
However the question still remains as posted as to whether or not ConfigureAwait(false) should be used at the top level.
The rule of thumb for ConfigureAwait(false) is to use it whenever the rest of your method doesn't need the context.
In ASP.NET, the "context" is not actually well-defined anywhere. It does include things like HttpContext.Current, user principal, and user culture.
So, the question really comes down to: "Does Controller.Json require the ASP.NET context?" It's certainly possible that Json doesn't care about the context (since it can write the current response from its own controller members), but OTOH it does do "formatting", which may require the user culture to be resumed.
I don't know whether Json requires the context, but it's not documented one way or the other, and in general I assume that any calls into ASP.NET code may depend on the context. So I would not use ConfigureAwait(false) at the top-level in my controller code, just to be on the safe side.

Calling await on a task created with Task.Run()

Why is it possible to do this in C#?
var task = Task.Run (...);
await task;
Isn't Task.Run() supposed to be used for CPU-bound code? Does it make sense to call awaitfor this?
I.e., after calling Task.Run I understand that the task is running in another thread of the thread pool. What's the purpose of calling await? Wouldn't make more sense just to call task.Wait()?
One last question, my first impression was that await is intended to be used exclusively with async methods. Is it common to use it for task returned by Task.Run()?
EDIT. It also makes me wonder, why do we have Task.Wait () and not a Task.Await(). I mean, why a method is used for Wait() and a keyworkd for await. Wouldn't be more consistent to use a method in both cases?
There would be no point at all in using Wait. There's no point in starting up a new thread to do work if you're just going to have another thread sitting there doing nothing waiting on it. The only sensible option of those two is to await it. Awaiting a task is entirely sensible, as it's allowing the original thread to continue execution.
It's sensible to await any type of Task (in the right context), regardless of where it comes from. There's nothing special about async methods being awaited. In fact in every single asynchronous program there needs to be asynchronous methods that aren't using the async keyword; if every await is awaiting an async method then you'll never have anywhere to start.
There are several good answers here, but from a more philosophical standpoint...
If you have lots of CPU-bound work to do, the best solution is usually the Task Parallel Library, i.e., Parallel or Parallel LINQ.
If you have I/O-bound work to do, the best solution is usually async and await code that is built around naturally-asynchronous implementations (e.g., Task.Factory.FromAsync).
Task.Run is a way to execute a single piece of CPU-bound code and treat it as asynchronous from the point of view of the calling thread. I.e., if you want to do CPU-bound work but not have it interfere with the UI.
The construct await Task.Run is a way to bridge the two worlds: have the UI thread queue up CPU-bound work and treat it asynchronously. This is IMO the best way to bridge asynchronous and parallel code as well, e.g., await Task.Run(() => Parallel.ForEach(...)).
why a method is used for Wait() and a keyword for await.
One reason that await is a keyword is because they wanted to enable pattern matching. Tasks are not the only "awaitables" out there. WinRT has its own notion of "asynchronous operations" which are awaitable, Rx observable sequences are awaitable, Task.Yield returns a non-Task awaitable, and this enables you to create your own awaitables if necessary (e.g., if you want to avoid Task allocations in high-performance socket applications).
Yes, it's common and recommended. await allows to wait for a task (or any awaitable) asynchronously. It's true that it's mostly used for naturally asynchronous operations (e.g. I/O), but it's also used for offloading work to be done on a different thread using Task.Run and waiting asynchronously for it to complete.
Using Wait not only blocks the calling thread and so defeats the purpose of using Task.Run in the first place, it could also potentially lead to deadlocks in a GUI environment with a single threaded synchronization context.
One last question, my first impression was that await is intended to be used exclusively with async methods
Whether a method is actually marked with the async modifier is an implementation detail and most "root" task returning methods in .Net aren't actually async ones (Task.Delay is a good example for that).
Wouldn't make more sense just to call task.Wait()?
No, if you call Wait you're involving two threads there, one of the worker threads from the ThreadPool is working for you (given the task is CPU bound), and also your calling thread will be blocked.
Why would you block the calling thread? The result will be too bad if the calling thread is a UI thread! Also if you call Task.Run immediately followed by Task.Wait you're making it worse, too. It is no better than calling the delegate synchronously. There is no point whatsoever in calling Wait immediately after starting a Task.
You should almost never use Wait, always prefer await and release the calling thread.
It is very common and useful for cases like (greatly simplified; production code would need exception handling, for instance):
async void OnButtonClicked()
{
//... Get information from UI controls ...
var results = await Task.Run(CpuBoundWorkThatShouldntBlockUI);
//... Update UI based on results from work run in the background ...
}
Regarding the comment of your later edit, 'await' is not a method call. It is a keyword (only allowed in a method that has been marked 'async', for clarity) that the compiler uses to decide how to implement the method. Under the hood, this involves rewriting the method procedure as a state machine that can be paused every time you use the 'await' keyword, then resumed when whatever is it awaiting calls back to indicate that it is done. This is a simplified description (exception propagation and other details complicate things), but the key point is that 'await' does a lot more than just calling a method on a Task.
In previous C# versions, the closest construct to this 'async/await' magic was the use of 'yield return' to implement IEnumerable<T>. For both enumerations and async methods, you want a way to pause and resume a method. The async/await keywords (and associated compiler support) start with this basic idea of a resumable method, then add in some powerful features like automatic propagation of exceptions, dispatching callbacks via a synchronization context (mostly useful to keep code on the UI thread) and automatic implementation of all the glue code to set up the continuation callback logic.

Categories

Resources