Go Concurrency Model: Goroutines & Channels
Core Philosophy: “Concurrency is not Parallelism”
As Rob Pike famously explained:
“Concurrency is about dealing with a lot of things at once. Parallelism is about doing a lot of things at once. Concurrency is about structure, parallelism is about execution.”
A concurrent program structures a problem into independently executing units that may or may not run in parallel depending on the hardware (CPU cores).
Key Components
1. Goroutines
- Extremely lightweight user-space threads managed by the Go runtime (M:N scheduler).
- Starts with a minimal stack size of just 2 KB (which grows and shrinks dynamically in contiguous memory blocks).
- Millions of goroutines can run concurrently on standard hardware, unlike OS threads which typically consume 1-8 MB each.
2. Channels
- Typed conduits through which concurrent goroutines communicate and synchronize without explicit mutexes.
- Based on the slogan: “Do not communicate by sharing memory; instead, share memory by communicating.”
- Supports unbuffered (synchronous rendezvous hand-off) and buffered (asynchronous queue up to capacity) channels.
3. The select Multiplexer
- Listens on multiple channel operations simultaneously, blocking until one is ready to proceed.
- Facilitates timeouts, cancellations (via
context.Context), non-blocking checks, and worker pool coordination.
Theoretical Roots
Go’s channel-based communication is an engineering realization of Tony Hoare’s 1978 formal paper: Communicating Sequential Processes (CSP).