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.
Related
I know the differences between a thread and a task., but I cannot understand if creating threads inside tasks is the same as creating only threads.
It depends on how you use the multithreaded capabilities and the asynchronous programming semantics of the language.
Simple facts first. Assume you have an initial, simple, single-threaded, and near empty application (that just reads a line of input with Console.ReadLine for simplicity sake). If you create a new Thread, then you've created it from within another thread, the main thread. Therefore, creating a thread from within a thread is a perfectly valid operation, and the starting point of any multithreaded application.
Now, a Task is not a thread per se, but it gets executed in one when you do Task.Run which is selected from a .NET managed thread pool. As such, if you create a new thread from within a task, you're essentially creating a thread from within a thread (same as above, no harm done). The caveat here is, that you don't have control of the thread or its lifetime, that is, you can't kill it, suspend it, resume it, etc., because you don't have a handle to that thread. If you want some unit of work done, and you don't care which thread does it, just that's it not the current one, then Task.Run is basically the way to go. With that said, you can always start a new thread from within a task, actually, you can even start a task from within a task, and here is some official documentation on unwrapping nested tasks.
Also, you can await inside a task, and create a new thread inside an async method if you want. However, the usability pattern for async and await is that you use them for I/O bound operations, these are operations that require little CPU time but can take long because they need to wait for something, such as network requests, and disk access. For responsive UI implementations, this technique is often used to prevent blocking of the UI by another operation.
As for being pointless or not, it's a use case scenario. I've faced situations where that could have been the solution, but found that redesigning my program logic so that if I need to use a thread from within a task, then what I do is to have two tasks instead of one task plus the inner thread, gave me a cleaner, and more readable code structure, but that it's just personal flair.
As a final note, here are some links to official documentation and another post regarding multithreaded programming in C#:
Async in Depth
Task based asynchronous programming
Chaining Tasks using Continuation Tasks
Start multiple async Tasks and process them as they complete
Should one use Task.Run within another Task
It depends how you use tasks and what your reason is for wanting another thread.
Task.Run
If you use Task.Run, the work will "run on the ThreadPool". It will be done on a different thread than the one you call it from. This is useful in a desktop application where you have a long-running processor-intensive operation that you just need to get off the UI thread.
The difference is that you don't have a handle to the thread, so you can't control that thread in any way (suspend, resume, kill, reuse, etc.). Essentially, you use Task.Run when you don't care which thread the work happens on, as long as it's not the current one.
So if you use Task.Run to start a task, there's nothing stopping you from starting a new thread within, if you know why you're doing it. You could pass the thread handle between tasks if you specifically want to reuse it for a specific purpose.
Async methods
Methods that use async and await are used for operations that use very little processing time, but have I/O operations - operations that require waiting. For example, network requests, read/writing local storage, etc. Using async and await means that the thread is free to do other things while you wait for a response. The benefits depend on the type of application:
Desktop app: The UI thread will be free to respond to user input while you wait for a response. I'm sure you've seen some programs that totally freeze while waiting for a response from something. This is what asynchronous programming helps you avoid.
Web app: The current thread will be freed up to do any other work required. This can include serving other incoming requests. The result is that your application can handle a bigger load than it could if you didn't use async and await.
There is nothing stopping you from starting a thread inside an async method too. You might want to move some processor-intensive work to another thread. But in that case you could use Task.Run too. So it all depends on why you want another thread.
It would be pointless in most cases of everyday programming.
There are situations where you would create threads.
I'm of the belief that you should never have to use Task.Run for any operation in .net core web context. If you have a long running task or CPU intensive task, you can offload it to a message queue for async processing. If you have a sync operation, that has no equivalent async method, then offloading to background thread does nothing for you, it actually makes in slightly worse.
What am I missing? Is there a genuine reason to use Task.Run in a high throughput server application?
Some quick examples:
A logging system where each worker thread can write to a queue and a worker thread is responsible for dequeuing items and writing them to a log file.
To access an apartment-model COM server with expensive initialization, where it may be better to keep a single instance on its own thread.
For logic that runs on a timer, e.g. a transaction that runs every 10 minutes to update an application variable with some sort of status.
CPU-bound operations where individual response time is more important than server throughput.
Logic that must continue to run after the HTTP response has been completed, e.g. if the total processing time would otherwise exceed an HTTP response timeout.
Worker threads for system operations, e.g. a long running thread that checks for expired cache entries.
Just to backup your belief:
Do not: Call Task.Run and immediately await it. ASP.NET Core already runs app code on normal Thread Pool threads, so calling
Task.Run only results in extra unnecessary Thread Pool scheduling.
Even if the scheduled code would block a thread, Task.Run does not
prevent that.
This is the official recommendation/best practice from Microsoft. Although it doesn't point out something you might have missed, it does tell you that it is a bad idea and why.
I would like to find out why the following needs to be blocked in order to get the console to write:
Task.Factory.StartNew(() => Console.WriteLine("KO"), TaskCreationOptions.LongRunning);
and this does not:
new Thread(() => Console.WriteLine("KO")).Start();
According to C# 5.0 in a nutshell, TaskCreationOptions.LongRunning is supposed to make the task NOT use pooled threads (which are background threads), meaning it should be using a foreground thread just like a regular thread, except with a regular thread, one does not need to Console.Readline or Wait() but with a Task, doesn't matter whether it's long running or not, I always have to block the main thread in some way.
So what good is LongRunning or OnComplete() or GetAwaiter() or GetResult() or any other function which is supposed to render a result If I always have to block the main thread myself to actually get the result?
You're relying on undefined behaviour. Don't do that.
You don't need to wait for a task to have it work - it's just the only way to be sure that it actually completed in some way. I assume you're just using a console application with nothing but the code above - by the time the thread actually gets to the Console.WriteLine part, the main thread is dead, and with it all the background threads. new Thread creates a foreground thread by default, which prevents the application as a whole from exiting, despite the fact that the "main" thread was terminated.
The idea behind tasks (and any kind of asynchronous operations, really) is that they allow you to make concurrent requests, and build chains of asynchronous operations (making them behave synchronously, which you usually want). But you still need points of synchronization to actually make a workable application - if your application exits before the tasks are done, too bad :)
You can see this if you just do a Console.ReadLine instead of waiting for the task to finish explicitly - it still runs in the background, independently of the main thread of execution, but now you give it enough time to complete. In most applications, you do asynchronous operations asynchronously to the main thread - for example, a result of a button click might be an asynchronous HTTP request that doesn't block the UI, but if the UI is closed, the request is still terminated.
Okay , let me try to put it in sentences ...
Lets consider an example,
where I create an async method and call it with await keyword,
As far as my knowledge tells me,
The main thread will be released
In a separate thread, async method will start executing
Once it is executed, The pointer will resume from last position It left in main thread.
Question 1 : Will it come back to main thread or it will be a new thread ?
Question 2: Does it make any difference if the async method is CPU bound or network bound ? If yes, what ?
The important question
Question 3 : Assuming that is was a CPU bound method, What did I achieve? I mean - main thread was released, but at the same time, another thread was used from thread pool. what's the point ?
async does not start a new thread. Neither does await. I recommend you read my async intro post and follow up with the resources at the bottom.
async is not about parallel programming; it's about asynchronous programming. If you need parallel programming, then use the Task Parallel Library (e.g., PLINQ, Parallel, or - in very complex cases - raw Tasks).
For example, you could have an async method that does I/O-bound operations. There's no need for another thread in this scenario, and none will be created.
If you do have a CPU-bound method, then you can use Task.Run to create an awaitable Task that executes that method on a thread pool thread. For example, you could do something like await Task.Run(() => Parallel...); to treat some parallel processing as an asynchronous operation.
Execution of the caller and async method will be entirely on the current thread. async methods don't create a new thread and using async/await does not actually create additional threads. Instead, thread completions/callbacks are used with a synchronization context and suspending/giving control (think Node.js style programming). However, when control is issued to or returns to the await statement, it may end up being on a different completion thread (this depends on your application and some other factors).
Yes, it will run slower if it is CPU or Network bound. Thus the await will take longer.
The benefit is not in terms of threads believe it or not... Asynchronous programming does not necessarily mean multiple threads. The benefit is that you can continue doing other work that doesn't require the async result, before waiting for the async result... An example is a web server HTTP listener thread pool. If you have a pool of size 20 then your limit is 20 concurrent requests... If all of these requests spend 90% of their time waiting on database work, you could async/await the database work and the time during which you await the database result callback will be freed... The thread will return to the HTTP listener thread pool and another user can access your site while the original one waits for the DB work to be done, upping your total limit.
It's really about freeing up threads that wait on externally-bound and slow operations to do other things while those operations execute... Taking advantage of built-in thread pools.
Don't forget that the async part could be some long-running job, e.g. running a giant database query over the network, downloading a file from the internet, etc.
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.