Go

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:

  1. It creates a sudog, joins the channel's recvq, and calls gopark. The G goes from Running to Waiting, and schedule() runs another G on the P.
  2. 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's runnext slot.
  3. 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

All 35 Goroutines & the Scheduler questions