Without any kind of async (this includes green threads) you run out of (OS) threads very fast.
This is not a black/white decision whether Async makes sense for every API all the time or never.
It's a solution to a specific problem that occurred (and still occurs) a lot.
The article was just about the syntax though, because they are still using asynchronous programming via coroutines (or goroutines ;-))
For all practical purposes goroutines behave as separate threads with blocking calls. The fact that they are multiplexed on a few system threads is an implementation detail.
Otherwise you could say that using system threads directly is also asynchrnous programming. After all, your thread gets suspended on system calls (including synchronization primitives) and is resumed upon their completion.
Semantically the biggest difference is that stackless coroutines typically require yield points to be marked syntactically in code.
What does run out mean?
Your program needs one million threads that sleep for 2 seconds, read some data and then finish. Guess what? Your execution is going to take hours, or get some kind of exception that you run out of threads because after the first ~6000 threads are taken, your OS can no longer give threads to anything else.
With Green threads, the threads are fake aka virtual and controlled by the language's runtime, be it JVM, CLR, Go's runtime etc. Runtime is usually smart enough to recognize sleeps and, while waiting for something, schedule another thread in its space.[1] So now all one million threads start near instantly and work almost all in parallel.
> Your program needs one million threads that sleep for 2 seconds, read some data and then finish.
I have yet to see this problem, but yeah I agree that millions is about when there will be problems.