Concurrency vs. parallelism in Go — can goroutines run in parallel with GOMAXPROCS=1?
Question 170MediumGo 1.22 to 1.25
Concurrency is about how a program is structured: independent tasks whose execution can interleave. Parallelism is about execution: several tasks running at literally the same moment on different cores. Rob Pike's phrase is "concurrency is not parallelism".
With GOMAXPROCS=1, only one goroutine executes Go code at a time, so goroutines run concurrently but not in parallel. Some things still happen alongside it:
- Goroutines blocked in syscalls or cgo run on their own threads while the P runs other Go code.
- The netpoller waits for I/O.
sysmonruns without a P.- GC background workers can use a fraction of the P. With a single P they run in time slices.
Gotcha: GOMAXPROCS=1 does not make racy code safe. Async preemption can switch goroutines between any two instructions, including in the middle of x++. Code has to be correct with synchronization regardless of GOMAXPROCS. Running tests with -cpu=1,4 and -race exposes these assumptions.
More on Goroutines & the Scheduler
- Q168What does this print? (Closure capture and the Go 1.22 loop variable change)
- Q169When does the Go runtime report "all goroutines are asleep - deadlock!" and when doesn't it?
- Q171What are the goroutine states and what transitions happen on a channel block?
- Q172How can you observe the scheduler? (schedtrace, go tool trace, pprof)
- Q173Why can many CPU-bound goroutines hurt performance, and how do you size a worker pool?
- Q174How do goroutines interact with cgo, and why can cgo calls be expensive?