Can async/await still deadlock if ConfigureAwait(false) is used? - c#

According to this link a deadlock can occur with async/await under particular scenarios.
However, can a deadlock still occur if I use ConfigureAwait(false) always?
For instance: task.ConfigureAwait(false).GetAwaiter().GetResult()
Instead of: task.GetAwaiter().GetResult()

It can still deadlock if whatever is going to complete task or any further nested operations have captured whatever your current context is, if that context is tied to a specific thread - because you're calling GetResult using that thread and blocking, making it unavailable for others to use still.
Just use await. It's await that can release your current context.

Yes it still can deadlock, ConfigureAwait(false) will have to be implemented in all the nested awaits, some of which you may not have control over.
The best approach is not to rely on it, just don't mix synchronous and async calls, let Async/Await propagate.
The only sure-fire way (and controversially) to make sure it wont deadlock (without await) is to offload / Wrap it to another task and Wait that, or be in a framework that doesn't have a SynchronizationContext

As the name implies, ConfigureAwait() only affects an asynchronous await. It has no effect on synchronous waits like Task.Wait(), Task.Result and Task.GetAwaiter().GetResult().
ConfigureAwait(false) means roughly "I don't care what thread the code after this async await will be resumed on", so if the original thread (more accurately SynchronizationContext) is blocked by something it will still continue on a different thread. But a synchronous wait like GetAwaiter().GetResult() doesn't ever switch threads.

Related

Task is asynchronous or synchronous without async await?

If I have task without async await, will my task consider asynchronous or synchronous? In Microsoft doc, it says The tasks run asynchronously and may complete in any order. but in one stackoverflow post, it says Wait will synchronously block until the task completes. So the current thread is literally blocked waiting for the task to complete.
Task is asynchronous or synchronous without async await?
That depends entirely on the Task itself, and will have nothing to do with whether you use await or not.
When you use Task.Run() to create a new task, that queues a worker to the thread pool, and it will run asynchronously. But, you can also get a Task object from the Task.FromResult() method, which trivially returns a completed task synchronously.
In between those two extremes are things like async methods that sometimes complete synchronously and sometimes don't (e.g. reading data from a file or network, where sometimes the data is already buffered and available and other times it won't be available until later).
The Stack Overflow post you mention doesn't have anything to do with the asynchronous nature of a task, but rather what happens depending on how you wait for the task to complete. Of course, synchronously-completed task objects are already completed by the time you have a reference to the object, so "waiting" on such an object never actually blocks anything. So the interesting case are task objects which are not already completed, i.e. which are going to complete asynchronously.
In those cases, the Wait() method will block the current thread. That's by design, and is clearly documented as such. This is almost never what you want. But it's important to note that even if you use Wait(), the task itself is still asynchronous. You may have blocked the current thread, but other things are still happening in your process, including whatever it is that task represents. Those things are happening asynchronously with your current thread.
The fact that you've chosen to make your current thread do nothing, doesn't change the inherently asynchronous nature of the task you started.
More typically, you will use await to effectively register your request to have the current method resume execution later, in the current synchronization context, once the task completes. At the await statement, the current method will yield the thread back to the caller, allowing it to go on to do other things. In that case, the task is still being completed asynchronously, just as if you'd used Wait() and blocked the thread, but now your current thread also has the opportunity to do something else.
In both cases, the task itself is still asynchronous. The way you've waited on it does not have any effect on that.
IMHO, it makes less sense to worry about whether the task is asynchronous or not. Your code should work the same regardless. Instead, view the task as a "promise" to provide a result at some point in the future. Indeed, the words "promise" and "future" are often used instead of "task" in other programming environments, to represent the same thing. Sometimes that promise is fulfilled immediately, sometimes it takes awhile, but it really doesn't matter to you which happens. What's important is the promise itself, not how or exactly when the promise will be kept.

Using Default ThreadPool SynchronisationContext in ASP.NET

Reading these two articles, SynchronisationContext and Async/Await. I'm very familiar with the way the ASP.NET SynchronisationContext handles the re-entry of async method execution back onto the request thread.
One of the big issues with re-entry is that if you use .Wait() or .Result you can cause a deadlock, why:
When the await completes, it attempts to execute the remainder of the async method within the captured context. But that context already has a thread in it, which is (synchronously) waiting for the async method to complete.
You get this because of the single thread that is being used by the SynchronisationContext and the way it permits only one chunk of code to run at a time.
What would be the implications of using Task.Factory.StartNew and assigning it a ThreadPool SynchronisationContext within an ASP.NET application?
I'm not bothered by why you would do this, rather more what would happen?
I know you are never supposed to Fire-and-Forget an async operation in ASP.NET because the thread may be cleared up before the async operation has completed. Would this also be true in the case of a ThreadPool SynchronisationContext.
What would be the implications of using Task.Factory.StartNew and assigning it a ThreadPool SynchronisationContext within an ASP.NET application?
There's no reason to use StartNew; Task.Run is superior in almost every use case. Also, you don't need to "assign" a thread pool SynchronizationContext, because thread pool threads have that naturally.
So, sure, you could do this:
await Task.Run(async () => { ... });
and all of your ... code will run on a thread pool thread (outside the request context), and resume on a thread pool thread (outside the request context).
This usage also doesn't have the problem of fire-and-forget, because our code is awaiting the result.
But I generally discourage this on ASP.NET, because think about what it's doing:
The code queues work (...) to the thread pool.
Then it asynchronously waits for that work to complete. During this time, the original request thread is returned to the thread pool.
When the work completes, the calling method continues in the request context.
So it causes an extra thread switch while giving you no benefit. It's possible to have a small amount of parallelism, but then you're talking about some potentially serious scalability limitations. Every time I've done parallelism on ASP.NET in production, I've ended up ripping it out.
I know you are never supposed to Fire-and-Forget an async operation in ASP.NET because the thread may be cleared up before the async operation has completed. Would this also be true in the case of a ThreadPool SynchronisationContext.
Actually, it's not because of a particular thread getting aborted. It's because the entire AppDomain is torn down. This includes aborting all threads.
So, yes, on ASP.NET, fire-and-forget using the thread pool is just as bad as any other kind of fire-and-forget:
Task.Run(() => ...); // bad!
At the very least, you should register the work with the ASP.NET runtime (which does not make the work reliable in the true sense of the word - it only minimizes the chance that the work will be aborted). Modern ASP.NET has HostingEnvironment.QueueBackgroundWorkItem for this.
Before ASP.NET added this method, I had a library that registered the work in a very similar way. I used Task.Run on purpose to run the registered work outside any request context and with a thread pool SynchronizationContext.

Task.Factory.New vs Task.Run vs async/await, best way to not block UI thread

I need to make sure some of my code runs in the background and doesn't stop block the UI thread, and I thought I knew how to use Task.Factory.New, but as I read more and more, it seems that it doesn't always create a new thread but sometimes runs it on the UI thread if the thread pool thinks that's the way to go so now I am pretty confused over what to use to be safe that the method is not blocking the UI thread. I should also add that I don't need a return value from the method , I just need it to run asynchronously ( in the background ).
So what's the difference between these methods below and what is best to use to make sure it doesn't block the UI thread ?
And is it really true that Task.Factory.StartNew doesn't always create a thread that runs in the background and doesn't block the UI?
public Form1()
{
Task.Factory.StartNew(() => Thread.Sleep(1000));
Task.Run(() => Thread.Sleep(1000));
Task<int> longRunningTask = LongRunningOperationAsync();
}
public async Task<int> LongRunningOperationAsync() // assume we return an int from this long running operation
{
await Task.Delay(1000);
return 1;
}
I should also add that I don't need a return value from the method
Beware of a common problem: just because you don't need a return value doesn't mean you shouldn't await the returned task. awaiting the task provides you with exception information as well. The only time it's appropriate to ignore the returned task is when you don't care about the return value and you don't care about any exceptions the background work may raise (that is, you're OK with silently swallowing them).
In easily >99% of cases, the appropriate behavior is to await the task.
So what's the difference between these methods below
StartNew is an outdated way to run code on a thread pool thread. You should use Run instead of StartNew. I describe why in painful detail on my blog, but the short answer is that StartNew does not understand async delegates and has inappropriate default options.
async is completely different. Run executes code on a thread pool thread, but async rewrites the code so that it doesn't need a thread while there's an asynchronous operation in progress. So, the Run example will block a thread pool thread for 1000ms in the Thread.Sleep call. The async example will run on the UI thread and then not use the UI thread for 1000ms in the await Task.Delay call.
and what is best to use to make sure it doesn't block the UI thread?
Both Task.Run and async are appropriate in UI apps, depending on the nature of the background code.
If your code is asynchronous (usually all I/O-bound code), then you should use async/await. Note that imposing asynchrony "top-down" is hard. Don't think about "forcing code off the UI thread"; instead, identify the naturally-asynchronous parts of your system (DB, file, WebAPI calls, etc), change them to be async at the lowest level, and work up from there.
If your code is synchronous (CPU-bound), then you can use Task.Run if it takes too long to run on your UI thread.
And is it really true that Task.Factory.StartNew doesn't always create a thread that runs in the background and doesn't block the UI?
Run always executes code on threads from the thread pool. The rules for StartNew are much more complex, but in your example example code, if TaskScheduler.Current == TaskScheduler.Default, then StartNew will also use a thread from the thread pool.
The two examples you give are pretty much the same and depend of the context you are using them on.
Tasks are a way to describe a packet of work with meta information to know about its state, synchronize multiple tasks, cancel them etc. The main idea about tasks and asynchronicity is that you don't have to care about "where" (on which thread) this unit of work is executed, it is performed asynchronously, that's all you need to know. So no worries for your UI-Thread, as long as you are working asynchronously, it won't be locked (that's one of the main improvements since Win8 and the async/await keywords, every UI Manipulation has to be async not to bloat the UI).
As for async&await, those are in fact syntactic sugar. In many simple cases, you don't need to care about the task itself, you just want the asynchronous computation "do this and give me the answer when you have it".
int x = await ComputeXAsync(); //Returns a Task<int> which will be automatically unwrapped as an int
If you need to synchronize tasks, for example start multiple tasks in parallel and wait that all of them are done before continuing, you can't rely on the simple await Task<int> format, you then need to work with the task itself, its Status property and in this case the Task.WaitAll(task[]) API.
Edit: I really recommend the chapter of JonSkeets Book C# in Depth (last edition). The Async/Await part is really well explained and will take you way further than any reading online will do.
The first two are actually the same. see here
Well you can think of it as a task is something you want to be done.
A thread is something like a worker which does the task for you. So basically a threads helps you doing a task, but it doesn't return a value.
a task does not create its own OS thread. Instead, tasks are executed by a TaskScheduler; the default scheduler simply runs on the ThreadPool.
See Here
An example is. A remote request you can do as task, you want the job done but dont know when it will be. But a TCPListener for the server I would run as a thread, because it always needs to listen to the socket.
Like Andreas Niedermair pointed out, you can also use longliving tasks with the TaskCreationOptions

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.

Why does task.Wait not deadlock on a non-ui thread? Or am I just lucky?

First a small bit of background information. I am in the process of making existing C# library code suitable for execution on WinRT. As a minor part of this code deep down needs to do a little file IO, we first tried to keep things synchronous and used Task.Wait() to stop the main thread until all IO was done.
Sure enough, we quickly found out that leads to a deadlock.
I then found myself changing a lot of code in a prototype to make it "asynchronous". That is, I was inserting async and await keywords, and I was changing the method return types accordingly. This was a lot of work - too much senseless work in fact -, but I got the prototype working this way.
Then I did an experiment, and I ran the original code with the Wait statement on a separate thread:
System.Threading.Tasks.Task.Run(()=> Draw(..., cancellationToken)
No deadlock!
Now I am seriously confused, because I thought that I understood how async programming works. Our code does not (yet) use ConfigureAwait(false) at all. So all await statements should continue in the same context as they got invoked in. Right? I assumed that that means: the same thread. Now if this thread has invoked "Wait", this should also lead to a deadlock. But it does not.
Do any of you have a clear rock-solid explanation?
The answer to this will determine whether I will really go through messing up our code by inserting a lot of conditional async/await keywords, or whether I will keep it clean and just use a thread that does a Wait() here and there. If the continuations get run by an arbitrary non-blocked thread, things should be fine. However, if they get run by the UI thread, we may be in trouble if the continuation is computationally expensive.
I hope that the issue is clear. If not, please let me know.
I have an async/await intro on my blog, where I explain exactly what the context is:
It is SynchronizationContext.Current, unless it is null, in which case it is TaskScheduler.Current. Note: if there is no current TaskScheduler, then TaskScheduler.Current is the same as TaskScheduler.Default, which is the thread pool task scheduler.
In today's code, it usually just comes down to whether or not you have a SynchronizationContext; task schedulers aren't used a whole lot today (but will probably become more common in the future). I have an article on SynchronizationContext that describes how it works and some of the implementations provided by .NET.
WinRT and other UI frameworks (WinForms, WPF, Silverlight) all provide a SynchronizationContext for their main UI thread. This context represents just the single thread, so if you mix blocking and asynchronous code, you can quickly encounter deadlocks. I describe why this happens in more detail in a blog post, but in summary the reason why it deadlocks is because the async method is attempting to re-enter its SynchronizationContext (in this case, resume executing on the UI thread), but the UI thread is blocked waiting for that async method to complete.
The thread pool does not have a SynchronizationContext (or TaskScheduler, normally). So if you are executing on a thread pool thread and block on asynchronous code, it will not deadlock. This is because the context captured is the thread pool context (which is not tied to a particular thread), so the async method can re-enter its context (by just running on a thread pool thread) while another thread pool thread is blocked waiting for it to complete.
The answer to this will determine whether I will really go through messing up our code by inserting a lot of conditional async/await keywords, or whether I will keep it clean and just use a thread that does a Wait() here and there.
If your code is async all the way, it shouldn't look messy at all. I'm not sure what you mean by "conditional"; I would just make it all async. await has a "fast path" implementation that makes it synchronous if the operation has already completed.
Blocking on the asynchronous code using a background thread is possible, but it has some caveats:
You don't have the UI context, so you can't do a lot of UI things.
You still have to "sync up" to the UI thread, and your UI thread should not block (e.g., it should await Task.Run(..), not Task.Run(..).Wait()). This is particularly true for WinRT apps.

Categories

Resources