Goroutines and the scheduler
How Go schedules concurrent work — and why you rarely tune GOMAXPROCS anymore.
Table of Contents
If you write Go long enough, “just add a goroutine” becomes muscle memory. Understanding what happens next is what separates intermediate from beginner code.
The model in one paragraph
Goroutines are cheap stack-switched tasks. The runtime multiplexes them onto OS threads (M) through processors (P). When a goroutine blocks on I/O, the runtime parks it and reuses the thread — no thread-per-request waste.
Starting work
results := make(chan int, 3)
for i := 1; i <= 3; i++ {
go func(n int) {
results <- n * n
}(i)
}
sum := 0
for i := 0; i < 3; i++ {
sum += <-results
}
When to care
- Default
GOMAXPROCSmatches your cores; override only with measured reason - Bounded buffers (
chan T, n) are your backpressure tool - If you can’t explain who closes a channel, redesign it
Part 2 builds on this with context and cancellation — the other half of production concurrency.