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 ?
awaitSome valuable answers for this question.