Skip to content

Chapter 5 of 7

Concurrency

Goroutines are Go's lightweight concurrency primitive. The go keyword starts a function as a goroutine that is multiplexed onto OS threads by the Go runtime, and each starts with only a few kilobytes of stack that grows on demand. Because goroutines are so cheap, programs routinely spawn tens of thousands of them. The runtime uses an M:N scheduler that maps M goroutines onto N OS threads, with logical processors (Ps) holding run queues and engaging in work stealing to keep cores balanced. GOMAXPROCS limits how many OS threads may execute Go code simultaneously and defaults to runtime.NumCPU(); it bounds parallelism, not concurrency. Go distinguishes between concurrency (structuring a program to handle many tasks) and parallelism (executing them simultaneously), and asynchronous preemption since Go 1.14 prevents a tight goroutine loop from starving the scheduler.

Channels are the primary way goroutines communicate safely. A channel is created with make(chan T) for an unbuffered channel or make(chan T, n) for a buffered one. Unbuffered channels synchronize sender and receiver: a send blocks until a receiver is ready and vice versa, so they act as a rendezvous point. Buffered channels allow sends up to capacity without blocking, only blocking when the buffer is full. Channels can be directional—chan<- T for send-only or <-chan T for receive-only—often used in function signatures to document intent. Only the sender should close a channel; receivers detect closure via the comma-ok idiom v, ok := <-ch or by ranging over the channel until it drains. A closed channel always yields the zero value immediately, while a nil channel blocks forever, and that contrast is used to dynamically disable select cases by assigning nil.

The select statement lets a goroutine wait on multiple channel operations at once, running the first case that becomes ready and falling through to default if none are. Combined with channels, select underpins many concurrency patterns: pipelines that chain producer and consumer stages; fan-out/fan-in designs that distribute work across multiple goroutines and merge results; worker pools that read jobs from a shared channel with a fixed number of goroutines; and coordination with context.Context for cancellation and deadlines. sync.WaitGroup waits for a collection of goroutines, sync.Mutex and sync.RWMutex protect shared state, sync.Once ensures one-time initialization, sync.Pool caches temporary objects to reduce allocations, and sync/atomic provides lock-free primitives like CompareAndSwap. The errgroup package from golang.org/x/sync ties multiple goroutines to a shared context and reports the first error, while singleflight collapses duplicate concurrent calls for the same key to prevent cache stampedes. Avoiding goroutine leaks requires cancelling blocked goroutines via context or by ensuring channels are eventually closed; otherwise they sit forever, wasting memory.

All chapters
  1. 1Language Fundamentals and Project Structure
  2. 2Composite Types and Data Structures
  3. 3Functions, Methods, and Interfaces
  4. 4Error Handling, defer, and Formatting
  5. 5Concurrency
  6. 6Standard Library: I/O, Encoding, Web, and Time
  7. 7Testing, Tooling, and Runtime Internals

Drill it

Reading is not remembering. These come from the Go Programming deck:

Q

What is Go (Golang)?

Go is an open-source programming language developed at Google by Robert Griesemer, Rob Pike, and Ken Thompson. It is statically typed, compiled, and designed fo...

Q

How do you declare a variable in Go?

You can declare variables using:var x int = 10var y = "hello" (type inferred)z := 42 (short declaration, only inside functions)

Q

What is a goroutine?

A goroutine is a lightweight thread managed by the Go runtime. You start one with the go keyword:go myFunction()Goroutines are multiplexed onto OS threads and a...

Q

How do you create a channel in Go?

Use the make function:ch := make(chan int) — unbufferedch := make(chan string, 5) — buffered with capacity 5Channels are used to communicate between goroutines...