As far as I know, Java's new virtual threads have the same idea.
It depends on the contract of the method. If it promises to throw an exception if the call failed, then the current thread of execution can't proceed before the call returns, or it would break the semantics. So even if it uses a thread pool, the current thread will have to block, waiting for some acknowledgement by os.write(), wasting an entire OS thread. As far as I know, Go won't block, the scheduler will just switch to a different goroutine in the meantime. Java's new virtual threads will allow to have mechanism similar to Go's.
there’s 2 language level syntax features i see that make this better:
one is scalas for comprehension. this lets you write async code that reads like imperative synchronous lines. the other is async/await, which let’s you write synchronous code that behaves like async
I didn't read the article but this TL;DR captures the essence of simplicity of programming in Go when writing IO apps. Go essentially optimizes for the majority case: run these things one after another. All the await/async fluff in other languages is evidence of poor/old language design. Every non-trivial production code you see these days in Javascript is littered with await/async as is the case in Python, etc. Why the heck do I have to repeat a keyword 1000s of times when that's expected in majority of languages.
Yes, Go may not cover every case perfectly (e.g. mentioned by sibling re CGO blocking OS thread), but when you look at real world stats of how often this is an actual issue, you find that it's almost noise (i.e. do a code search across Github for instance for such workarounds).
Go: fmt.Fprintln(w, "Goodbye, World!")
Java: os.write(response.getBytes());
I also can’t quite grasp the comparison with Java. It’s passing a class instance to the server handler, and that could be doing anything. Nothing there tells you how async or not the server implementation is, and that `os.write()` call might be using a thread pool underneath.