
What the Go scheduler does when your goroutine blocks
A blocking syscall costs an OS thread. A blocking network read costs nothing. Measured with 200 goroutines, GOMAXPROCS=2 and a thread count.
A Go publication by Nolan Keir
Deep dives into the Go runtime, concurrency, performance, and the trade-offs behind clean abstractions.

A blocking syscall costs an OS thread. A blocking network read costs nothing. Measured with 200 goroutines, GOMAXPROCS=2 and a thread count.
Go 1.27's size-specialised allocation is worth up to 46% on the pointer-containing path, not the 30% announced — and from 96 bytes up it is worth nothing.
A gctrace line carries eleven numbers. Two are stop-the-world, one has a third of the GC subtracted out of it, and the biggest one is not a pause at all.
One heap shape lost 63% of its collector CPU and gained 14% throughput. Another gained 39% collector CPU and lost nothing. Same flag, same binary pair, same machine.
GOGC=100 with a 256 MiB limit produced exactly what GOGC=off produced: same collections, same CPU share, same throughput. The tighter rule binds, the other goes quiet.
A static route through net/http's mux costs 85.6 ns and nothing on the heap. A path that matches no pattern costs 2125.5 ns and 62 allocations.
One goroutine: 2.5 ns for the mutex, 172.6 ns for the channel. Sixteen goroutines with real work: the channel wins by less than the harness's own error.
Series4 parts
Starts with: What the Go scheduler does when your goroutine blocks
Series1 part
Starts with: The 30% is 46%, and it stops dead at 80 bytes