I have been reading a bit about async/await vs ThreadPool vs Threads, and I have to admit, I'm not fully clear on the details. There is one specific question that I think I have the answer to, but I can't say for sure.
I am also aware of the many many questions on SO and elsewhere, where these questiosn are being discussed and explained. I have read a fair few here on SO, but I haven't found a clear answer, or at least as clear as I'd like.
What I gathered:
However, a collegue said something like this:
So, what I am asking is:
Please note that I am not discussing the client-side of things, just from a server perspective.
And sorry in advance if I missed an exact answer to this, I have looked =)
The real issue is not "thread pool vs. async/await", it's synchronous I/O vs. asynchronous I/O. [1]
On Windows, threads are relatively expensive objects -- a thread has a lot of OS bookkeeping associated with it, not to mention 1 MB of preallocated stack space. This puts a fairly low cap on how many threads the system will even support, and even when you don't hit that cap, context switching between all those threads is not cheap either. That "32,000 threads" limit is a strictly theoretical one, and highly optimistic about how many threads you can have and still be responsive! [2]
Enter asynchronous I/O, which is optimized to use only as many threads as necessary (usually some conservative multiple of the number of physical processor cores in the system), ideally never even creating new threads beyond the initial batch. These threads are dedicated to handling completed I/O operations by removing them from a queue (known as a completion port). While an asynchronous operation is in progress, no thread is dedicated to it at all, not even as an item on a wait list (Stephen Cleary has a nice blog post about it that explains this in more detail). Not much imagination is needed to think about what's more efficient:
As it turns out, the latter scales much better than the former; the "thread per request" model which is common in naive server code quickly shows its limits, even when you use a thread pool to reduce the creation of new threads. Note that this was an issue long before async/await was ever a thing, and so is the solution Windows went with; async/await is just a new way of writing code to use the existing mechanisms.
Are you likely to notice a difference with only a few requests in flight at a time? No. But since async/await essentially allows you to write code that looks synchronous but has the scalability of asynchronous I/O "for free", why would you not choose to use that in favor of synchronous I/O queued to the thread pool?
[1] Turns out Stephen Cleary already wrote most of what's in this answer a few years ago. I recommend you read that as well.
[2] Here's an older post by Mark Russinovich where he actually tries to squeeze as many threads out of the system as possible -- just for fun and profit. He "only" gets to 55K on a 64-bit machine before all resources are gone, and that's with adjusting the default stack size, and without doing any actually useful work. On a modern system you could probably get more, but the real question should not be "how many threads can I have" -- if it is, you're Doing it Wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With