0

I suppose, there is a thread pool which the web server are using to serve requests. So the controllers are running within one of the thread of this thread pool. Say it is the 'serving' pool.

In one of my async action method I use an async method,

var myResult = await myObject.MyMethodAsync();
// my completion logic here

As explained many places, we are doing this, to not block the valuable serving pool thread, instead execute MyMethodAsync in an other background thread... then continue the completion logic in again a serving pool thread, probably in other one, but having the http context, and some othe minor things marshaled there correctly.

So the background thread in which MyMethodAsync runs must be from an other thread pool, unless the whole thing makes no sense.

Question

Please confirm or correct my understanding and in case if it is correct, I still miss why would one thread in one pool more valuable resource than other thread in another pool? In the end of the day the whole thing runs on a same particular hardware with given number of cores and CPU performance...

g.pickardou
  • 32,346
  • 36
  • 123
  • 268
  • There are a limited amount of threads available to serve requests. If your logic is executed on these threads they are unavailable for other requests. When working async you work on another thread from another pool so the request thread is available again to serve other requests. – lordvlad30 Feb 17 '23 at 06:05
  • OK, but at the and of the day the server hw also has a particular limited capacity, so what is the use to split the thread to two pools? – g.pickardou Feb 17 '23 at 06:10
  • Being able to serve more requests at once. I will link the following (as this question is already asked before) with more info: [should I use async await](https://stackoverflow.com/a/61154255/5632166). And yes hardware is also a limit for performance and with good software/code we utilize the hardware as best as possible – lordvlad30 Feb 17 '23 at 06:17

1 Answers1

2

There is only one thread pool in a .NET application. It has both worker threads and I/O threads, which are treated differently, but there is only one pool.

I suppose, there is a thread pool which the web server are using to serve requests. So the controllers are running within one of the thread of this thread pool. Say it is the 'serving' pool.

ASP.NET uses the .NET thread pool to serve requests, yes.

As explained many places, we are doing this, to not block the valuable serving pool thread, instead execute MyMethodAsync in an other background thread... then continue the completion logic in again a serving pool thread, probably in other one, but having the http context, and some othe minor things marshaled there correctly.

So the background thread in which MyMethodAsync runs must be from an other thread pool, unless the whole thing makes no sense.

This is the wrong part.

With truly asynchronous methods, there is no thread (as described on my blog). While the code within MyMethodAsync will run on some thread, there is no thread dedicated to running MyMethodAsync until it completes.

You can think about it this way: asynchronous code usually deals with I/O, so lets say for example that MyMethodAsync is posting something to an API. Once the post is sent, there's no point in having a thread just block waiting for a response. Instead, MyMethodAsync just wires up a continuation and returns. As a result, most asynchronous controller methods use zero threads while waiting for external systems to respond. There's no "other thread pool" because there's no "other thread" at all.

Which is kind of the point of asynchronous code on ASP.NET: to use fewer threads to serve more requests. Also see this article.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810
  • Many thx for your detailed answer. It seems you dealt with this very question 10 years before in your blog. It also seems you had to argue on this many times, even before you wrote your blog, hence the tone... Anyway, the OS async IO and a modern OS behavior to spare its resources is pretty well known to professionals. However I found weak point of the whole argument is the cloudy definition of "truly asynchronous"... – g.pickardou Feb 18 '23 at 06:36
  • ...If that async method written by a developer in C#, using the Task library (either you, either me, or an open source third party library or even in MS Team), then will be a prolog, epilog code which must be run in a particular thread. var i = 0; within an async method will not be run in the thin air... OK, I understand this method is not a "truly asynchronous" method instead a hybrid of executable C# statements mixed with one or more further async method calls, which are also may "truly async" or hybrid and so on... So what about those async methods in real life? – g.pickardou Feb 18 '23 at 06:36
  • I did not mean to have an argumentative tone at all; I never mind explaining things. Code statements are run on threads; see my [`async` intro](https://blog.stephencleary.com/2012/02/async-and-await.html) for details on which thread(s) are used. By "truly asynchronous", I mean methods that have a point where there are no threads being used. This is in contrast to methods that are synchronous (always returns a completed task) or "fake asynchronous" (just runs synchronous code on a thread pool thread). – Stephen Cleary Feb 18 '23 at 13:26
  • so the question still remains, with real life async/await. For example EF Core `context.SaveChangesAsync()` just to mention a widely used. Even it could have real async parts, when waiting to complete the network, it has prologue and epiloge boilerplate C# code, in which thread will it run? – g.pickardou Feb 19 '23 at 05:09
  • 1
    As explained [on my blog](https://blog.stephencleary.com/2012/02/async-and-await.html), `async` methods begin executing on the calling thread until they hit an asynchronous `await`, at which point there is no thread. Later, they continue executing on the `SynchronizationContext` or `TaskScheduler` that was current at the time of the `await`. – Stephen Cleary Feb 20 '23 at 12:06
  • Is a database operation considered real async (in somewhere in deep in `context.SaveChangesAsync()`? – g.pickardou Feb 21 '23 at 04:30
  • Yes, it is, because it sends the db command and then waits for a response. – Stephen Cleary Feb 21 '23 at 12:09
  • many thx for your patience. Some light seems to be appear on the horizon... – g.pickardou Feb 21 '23 at 15:38