One needs something like async in pretty much all languages. It's either that or use threads.
Consider you want to do something like this (In a sort of Javascript like pseudo code)
function readStreamA (a) {
while true {
print (a.read); // Read waits for a to get data.
}
}
function readStreamB (b) {
while true {
print (b.read); // Read waits for b to get data.
}
}
readStreamB(a)
readStreamB(b)
Clearly this will not work. If readStreamA waits forever for data then, execution stops in the read call. The function never returns. readStreamB never happens. And vice versa and etc.
To get around this one might use threads to run the functions instead.
thread.spawn (readStreamB(a))
thread.spawn (readStreamB(b))
Here the spawn creates a thread to start each function which then run around forever. If one is waiting the other can proceed when it has data.
Creating threads is a heavy weigh, time and space consuming mechanism. If you need thousand of threads you will use a lot of memory in their stacks. You will waste a lot of time swapping the CPU from running one to another (scheduling overheads)
To do this more efficiently one want to run many of those loops on a single core. After all, they are doing nothing but waiting most of the time. Javascript does this with it's event loop. which runs everything on a single thread and uses call back functions to run bits of code when data arrives:
a.on_data (function (data) {
print (data) // Lamda function called when a has data
}
}
a.on_data (function (data) {
print (data) // Lamda function called when a has data
}
}
As JS only has one thread, clearly long computations in any of those event handlers will hang up everything and cause problems.
The whole idea of async is to do what javascript is doing but without all that messy call back handler syntax.
But of course we do actually have many cores now a days, so why spread the work around for performance. Enter the thread pools!
I'm not sure any of this async stuff is actually ever necessary unless you do actually need thousands of threads in your program. Async should be avoided otherwise. Regular threads are just fine and simple in many cases, especially if you a lot of compute work to do.
As the async book says in it's introduction:
"It's important to remember that traditional threaded applications can be quite effective, and that Rust's small memory footprint and predictability mean that you can get far without ever using async
. The increased complexity of the asynchronous programming model isn't always worth it, and it's important to consider whether your application would be better served by using a simpler threaded model."
https://rust-lang.github.io/async-book/01_getting_started/02_why_async.html