Let's suppose that a goroutine is reading from the network. Every time the goroutine has to wait (gets blocked waiting for the network to respond), what happens? Does the OS thread running the goroutine get blocked? Or does it work like an async operation in C# (where the thread returns to the thread pool until the IO thread of the operative system notifies the program that there's new data to process, and then, another thread from the thread pool continues processing the data received from the network)?
My main worry is that if Go keeps a blocked thread every time a goroutine gets blocked, if I have many goroutines in a server processing incoming connections from a very slow network, I may end up running out of RAM, since each one of those blocked threads consumes about 2MB of RAM. Or if the thread pool created by Go to run goroutines has a limit, I may end up running out of liveliness.
So how do goroutines behave in IO bound operations?
If it's an async syscall, it blocks the goroutine and frees the thread to run another goroutine, same as if the goroutine is blocking on e.g. a channel read.
If it's a blocking syscall, there's nothing Go can do about that - the syscall will block the thread, period. Go may spin up another thread to handle runnable goroutines as determined by the scheduler.