Coroutines
Threads are the most common way to implement concurrency in most languages and use cases, but they are expensive in terms of cost, and while ThreadPool
can be a good solution for cases when thousands of threads are involved, it's usually unreasonable to involve thousands of threads. Especially when long-lived I/O is involved, you might easily reach thousands of operations running concurrently (think of the amount of concurrent HTTP requests an HTTP server might have to handle) and most of those tasks will be sitting doing nothing, just waiting for data from the network or from the disk most of the time.
In those cases, asynchronous I/O is the preferred approach. Compared to synchronous blocking I/O where your code is sitting there waiting for the read or write operation to complete, asynchronous I/O allows a task that needs data to initiate the read operation, switch to doing something else, and once the data is available, go back to what it was doing.
In some cases, the notification...