I know that is a common question, but I've read a kiloton of articles and feel confused. And now I think that it would be better not to read them at all )).
So, how ASP.NET works (only about threads):
http request is served by thread from the thread pool.
while request is processing this thread is busy, because request is processing inside exactly this thread.
when request processing finishes, the thread returns to thread pool, server sends a response.
Is this described behaviour right ?
What really happens when I start new task inside ASP.NET MVC controller?
public ActionResult Index()
{
var task1 = Task.Factory.StartNew(() => DoSomeHeavyWork());
return View();
}
private static async Task DoSomeHeavyWork()
{
await Task.Delay(5000);
}
controller action starts to execute inside thread that processes current request - T1.
the thread pool allocates another one thread (T2) for task1.
task1 starts "immediately" inside T2.
the View result returns "immediately".
ASP.NET do some work, server sends a response, T1 returns to the thread pool, T2 is still alive.
after some time when the DoSomeHeavyWork will be finished, the T2 thread will be returned to the thread pool.
Is it correct ?
Now lets look to async action
public async Task<ActionResult> Index()
{
await DoSomeHeavyWork();
return View();
}
, I understand the difference with previous code sample, but not the process, in this example the behaviour is the following:
action starts to execute inside thread that processes current request - T1.
DoSomeHeavyWork "immediately" returns a task, let's call it "task1" too.
T1 returns to the thread pool.
after the DoSomeHeavyWork finishes, Index action continue to execute.
after Index action execution the server will send a response.
Please explain what happening between points 2 and 5, the questions are:
is the DoSomeHeavyWork processed inside task1 or where (where it is "awaited") ? I think this a key question.
which thread will continue to process the request after await - any new one from the thread pool, right ?
request produces thread allocating from the thread pool, but response will not be sent until the DoSomeHeavyWorkAsync finished and it doesn't matter in which thread this method executes. In other words, according to single request and single concrete task (DoSomeHeavyWork) there is no benefits of using async. Is it correct ?
if the previous statement is correct, then I don't understand how the async can improve performance for multiple requests with the same single task. I'll try to explain. Let's assume that the thread pool has 50 threads available to handle requests. Single request should be processed at least by one single thread from the thread pool, if the request starts another threads, then all of them will be taken from the thread pool, e.g. request takes one thread to process himself, starts 5 different tasks in parallel and wait all of them, thread pool will have 50 - 1 - 5 = 44 free threads to handle incoming requests - so this is a parallelism, we can improve performance for single request, but we reduce number of requests which can be processed. So according request processing in ASP.NET I suppose that only task that somehow starts IO completion thread can achieve a goal of async (TAP). But how IO completion thread calls back thread pool thread in this case ?
Is this described behaviour right ?
Yes.
Is it correct ?
Yes.
is the DoSomeHeavyWork processed inside task1 or where (where it is
"awaited") ? I think this a key question.
From the current code, DoSomeHeavyWork will asynchronously wait for Task.Delay to complete. Yes, this will happen on the same thread allocated by the thread-pool, it won't spin any new threads. But there isn't a guarantee that it will be the same thread, though.
which thread will continue to process the request after await?
Because we're talking about ASP.NET, that will be an arbitrary thread-pool thread, with the HttpContext marshaled onto it. If this was WinForms or WPF app, you'd be hitting the UI thread again right after the await, given that you don't use ConfigureAwait(false).
request produces thread allocating from the thread pool, but response
will not be sent until the DoSomeHeavyWorkAsync finished and it
doesn't matter in which thread this method executes. In other words,
according to single request and single concrete task (DoSomeHeavyWork)
there is no benefits of using async. Is it correct ?
In this particular case, you won't see the benefits of async. async shines when you have concurrent requests hitting the server, and alot of them are doing IO bound work. When using async while hitting the database, for example, you gain freeing the thread-pool thread for the amount of time the query executes, allowing the same thread to process more requests in the meanwhile.
But how IO completion thread calls back thread pool thread in this
case ?
You have to separate parallelism and concurrency. If you need computation power for doing CPU bound work in parallel, async isn't the tool that will make it happen. On the other hand, if you have lots of concurrent IO bound operations, like hitting a database for CRUD operations, you can benefit from the usage of async by freeing the thread while to IO operation is executing. That's the major key point for async.
The thread-pool has dedicated pool of IO completion threads, as well as worker threads, which you can view by invoking ThreadPool.GetAvailableThreads. When you use IO bound operations, the thread that retrieves the callbacks is usually an IO completion thread, and not a worker thread. They are both have different pools.
Related
I was reading the documentation of Microsoft specifically the Async programming article and I didn't understand this section while he is explaining the work of the server's threads when using Async code.
because it(The server) uses async and await, each of its threads is freed up when the I/O-bound work starts, rather than when it finishes.
Could anyone help what does it mean by the threads r freed up when the I/O starts??
Here is the article : https://learn.microsoft.com/en-us/dotnet/standard/async-in-depth
When ASP.NET gets an HTTP request, it takes a thread from the thread pool and uses that to execute the handler for that request (e.g., a specific controller action).
For synchronous actions, the thread stays assigned to that HTTP request until the action completes. For asynchronous actions, the await in the action method may cause the thread to return an incomplete task to the ASP.NET runtime. In this case, ASP.NET will free up the thread to handle other requests while the I/O is in flight.
Further reading about the difference between synchronous and asynchronous request handling and how asynchronous work doesn't require a thread at all times.
When your application makes a call to an external resource like Database or HttpClient thread, that initiated connection needs to wait.
Until it gets a response, it waits idly.
In the asynchronous approach, the thread gets released as soon as the app makes an external call.
Here is an article about how it happens:
https://medium.com/#karol.rossa/asynchronous-programming-73b4f1988cc6
And performance comparison between async and sync apporach
https://medium.com/#karol.rossa/asynchronous-performance-1be01a71925d
Here's an analogy for you: have you ever ordered at a restaurant with a large group and had someone not be ready to order when the waiter came to them? Did they bring in a different waiter to wait for him or did the waiter just come back to him after he took other people's orders?
The fact that the waiter is allowed to come back to him later means that he's freed up immediately after calling on him rather than having to wait around until he's ready.
Asynchronous I/O works the same way. When you do a web service call, for example, the slowest part (from the perspective of the client at least) is waiting for the result to come back: most of the delay is introduced by the network (and the other server), during which time the client thread would otherwise have nothing to do but wait. Async allows the client to do other things in the background.
Service layer
public async Task<string> getAllAsync()
{
return await WCFMethodAsync();
}
Presentation layer
public class Customer : Controller
{
public async Task<string> Index()
{
var r = await Task.Run(getAllAsync());
return r;
}
}
I will describe what I think is happening. I would like to know if I am wrong.
the request takes a thread from ThreadPool
await returns an incomplete Task
Task.Run queues a Task to run getAllAsync
3.1. that will take a thread from the ThreadPool.
when the getAllAsync method finishes the taken thread returns to the group of threads
when the service method call end .net is notified and a thread is taken from the group of threads o terminate the request.
Where is the incomplete homework returned to? Since the method was executed inside Task.Run.
I would like to know the flow of the whole process.
Since a thread was initially taken from the thread group and task.run takes a work thread, the question is when the task ends the job (wcf) and a thread is taken to finish the request. How many threads were used to process the request?
Your getAllAsync method is a I/O bound operation, because you are making a network call to reach your WCF service instance.
That means the getAllAsync will be executed by the network driver. It is an asynchronous non-blocking promise task. The calling thread is not blocked until the asynchronous I/O operation finishes. When it finishes the ThreadPool will be notified about it.
On the other hand the Task.Run is design for CPU bound operation.
The Task.Run returns a delegate task and it is used to queue a work on the ThreadPool. That work will be processed by one of the CPU core.
So if you put an asynchronous I/O work (kick-off) call on a dedicated Thread then that is just wasting valuable resources.
I have a variation of the benefits-of-async/await-on-ASP.NET from this question.
My understanding is that asynchrony is not the same thing as parallelism. So, on a web server, I wonder about how much benefit async/await brings to ASP.NET pages.
Isn't IIS+ASP.NET already really good at allocating threads for requests, and if onen page is busy waiting for a resource the server will just switch to processing another request that has work to do?
There are a limited number of threads in the pool for ASP.NET to use - does async use them any more effectively?
As Mr. Skeet pointed out in answering the question above, we're not talking about blocking a UI thread. We're already multi-threaded and the web response can't be completed until all the request's tasks are done, async or not, right?
I guess what it boils down to is this:
Is there any benefit to an async read of a resource (say a file or DB request) in an ASP.NET page vs. blocking on it?
if one page is busy waiting for a resource the server will just switch to processing another request that has work to do?
I don't think so. I would be very surprised if this were the case. It's theoretically possible, but very complex.
There are a limited number of threads in the pool for ASP.NET to use - does async use them any more effectively?
Yes, because when you await something, the thread for that request is immediately returned to the pool.
We're already multi-threaded and the web response can't be completed until all the request's tasks are done, async or not, right?
That is correct. async in a server scenario is all about removing pressure on the thread pool.
Is there any benefit to an async read of a resource (say a file or DB request) in an ASP.NET page vs. blocking on it?
Absolutely!
If you block on a file/service call/db request, then that thread is used for the duration of that operation. If you await a file/service call/db request, then that thread is immediately returned to the thread pool.
One (really cool!) result of this is that you can have a request in progress, and while it's (a)waiting some operation, there are no threads servicing that request! Zero-threaded concurrency, if you will.
When the operation completes, the method resumes after the await - on a (possibly different) thread from the thread pool.
In conclusion: async scales better than threads, so there is definitely a benefit on the server side.
More info: my own intro to async post and this awesome video.
I'm implementing Comet in ASP.NET MVC. I used a timer to keep an async request in the server. The async request will complete when the timer elapses after 1 minute and sends a response to the client (to avoid 404 error) and then reconnects to Async Controller.
I also want to execute some synchronous actions while the async request was holding, but the problem is:
When an async action was executed and hold by using timer, the sync action wasn't called until the async action (Comet long-live request) completed.
I did the test with Firefox 3.6 many times, but the result is always the same; it is so strange. Do you know why?
I have a sub-question:
To implement Comet, using a timer (response after some minutes elapsed) or thread (response after several time sleeping thread) to hold async request; which is better?
I found the answer for my problems.
First,the reason why Sync action wasn't executed while Async action holding because session request block mechanic, Asp.net session block request so that all requests will be process one by one even you use concurrent request with Ajax Async Call. And the solution is disable session on controller you want to hold long-live request. Here is detail explanation: https://blogs.msdn.com/b/rickandy/archive/2009/12/17/session-less-mvc-controller.aspx
The second, when perform holding long-live request,using timer and thread sleeping are NOT different, because Asp.net thread pool will essentially create new thread to track time elapsed and call back to your timer elapsed event. It will decrease number of threads to serve request in thread pool because it born new thread to track timer event.
I was working on a project and there is bulk e-mail sending part of it and when user clicks on the button, he/she gets the "Thanks the e-mails have been sent" immediately as a Response and the same method is firing an async thread as well.
ThreadPool.QueueUserWorkItem(SendEMail, _message);
This thread is queued when user clicks on the send button but since this is default Background Thread I was expecting when the page response ended, this thread would be terminated but it didn't happen because the current thread which fires this Thread was also a Background Thread and a Worker Thread, so which means there is an unfinished foreground thread(s) (Could be MainThread or Worker Threads) still alive but I don't know when they finish because their finish time will effect my background worker threads; When the last foreground thread ends, it causes the process to be terminated, so do background threads.
Should I be afraid of this or Asp.NET can handle it automatically and I am kinda confused because I've read a lot of things about it and now everything is mixed up.
Could you please clarify things a little bit ?
Thanks in advance.
Using the ThreadPool for long-running tasks will negatively influence the performance of your application (because ASP.NET also uses the ThreadPool to handle incoming requests).
Creating threads manually for each task can also become a problem if too much threads are created.
One technique I've used in the past, is to create a custom ThreadPool when starting the application, and enqueuing tasks on that ThreadPool. A simple custom ThreadPool could consist of a single Thread and a Queue of tasks.
When you call QueueUserWorkItem a new thread will be drawn from the thread pool if available and execute the callback function on this thread. If no threads are available, the function will block until a thread is freed. Once it finishes the execution of the method the thread will be suspended and returned to the pool for further reuse. Your only concern should be the fact that threads from the pool are also used to service requests, so if you perform lengthy tasks on them you could jeopardize the whole system request servicing capabilities because there's a limited number of threads in the pool and if all of them are busy performing lengthy operations future HTTP requests will be queued. As an alternative you could consider creating threads manually: new Thread(state => { }).Start();
You can use MSMQ for creating your email queue and have a single thread process the queue.
The following post might be useful as it fits your problem domain. Although it does not use MSMQ but is a good post on processing scheduled tasks using ASP.net.
Simulate a Windows Service using ASP.NET to run scheduled jobs