The end result is much easier than Python/NodeJs because there is no explicit "async/await" or deferred-style programming. You simply write linear code and any blocking operation (at the syscall level) is transparently handled.
The end result is much easier than Python/NodeJs because there is no explicit "async/await" or deferred-style programming. You simply write linear code and any blocking operation (at the syscall level) is transparently handled.
There's nothing semantically unique to Go about this model.
There have been implementations of pthreads that used an M:N model, for instance.
I'm not convinced that 1:1 wouldn't have been a perfectly reasonable implementation strategy for Go.
Semantically, a goroutine is a thread, within a shared memory model. But what makes Go unique (or let's say more unique) is that it offers programmers a thread-like programming approach (linear, blocking code) but internally turns it into an event-driven approach (epoll/kqueue) for networking.
Moreover, the fact that goroutines are much cheaper than OS-level threads enable a more pervasive approach to concurrency.