How Go Evolved from Cooperative to Signal-Based Goroutine Scheduling
Go's concurrency model relied on cooperative preemption at function prologues until version 1.10, allowing goroutine switches only at compiler-inserted safe points to support precise garbage collection. This approach caused serious issues, including cases where a goroutine spinning on an atomic load could starve other goroutines and halt the program entirely. Attempts to fix this by adding preemption checks at loop back-edges proved costly, with the most efficient method still slowing benchmarks by a geomean of 7.8% while introducing debugger conflicts. Starting with Go 1.14, the language switched to signal-based non-cooperative preemption, using the POSIX signal SIGURG to interrupt running goroutines and capture their CPU state without requiring their cooperation. SIGURG was chosen because it is debugger-friendly, not used by libc in mixed Go/C binaries, and largely irrelevant in modern applications due to the near-obsolescence of out-of-band socket data.
This is an AI-generated summary. ShortSingh links to the original source for the complete article.
Discussion (0)
Log in to join the discussion and vote.
Log in