What are the goroutine states and what transitions happen on a channel block?
Question 171HardGo 1.22 to 1.25
The main G states in runtime2.go:
_Gidle: just allocated._Grunnable: in a run queue._Grunning: owns an M and a P._Gsyscall: in a syscall, owns an M but may lose its P._Gwaiting: parked on a channel, mutex, timer, netpoll or GC._Gdead: finished, and kept on a free list for reuse._Gcopystack: its stack is being moved._Gpreempted: suspended by async preemption.
When a goroutine receives on an empty channel:
- It creates a
sudog, joins the channel'srecvq, and callsgopark. The G goes from Running to Waiting, andschedule()runs another G on the P. - A sender finds the waiting sudog and copies the value directly onto the receiver's stack, skipping the buffer. It then calls
goready: Waiting to Runnable, into the sender P'srunnextslot. - Because of
runnext, the receiver usually runs next on the same P, which keeps caches warm. Ping-pong between two goroutines therefore stays on one P.
A stack dump shows the wait reason, for example goroutine 7 [chan receive, 3 minutes]:, which is what you look for when hunting leaks.
More on Goroutines & the Scheduler
- Q169When does the Go runtime report "all goroutines are asleep - deadlock!" and when doesn't it?
- Q170Concurrency vs. parallelism in Go — can goroutines run in parallel with GOMAXPROCS=1?
- 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?
- Q175Implement a bounded, cancellable fan-out that returns the first error and does not leak goroutines.