thecodex.expert · The Codex Family of Knowledge
Go

Concurrency Patterns

The same two primitives — goroutines and channels — combine into every common concurrency shape: worker pools, pipelines, fan-out, fan-in.

Go 1.26 Worker pools Last verified:
Canonical Definition

Go’s concurrency patterns are combinations of goroutines and channels rather than named framework constructs: a worker pool is a fixed number of goroutines pulling from a shared job channel; a pipeline chains stages together via channels, each stage a goroutine reading from one channel and writing to the next; fan-out spreads work across multiple goroutines, and fan-in merges multiple channels back into one.

Worker pool: a fixed number of goroutines sharing jobs

Rather than launching one goroutine per task (which could spawn thousands unpredictably), a worker pool launches a fixed number of goroutines that all read from the same jobs channel, naturally load-balancing work across them.

Goworker_pool.go
func worker(id int, jobs <-chan int, results chan<- int) {
    for j := range jobs {           // exits automatically when jobs is closed
        results <- j * 2
    }
}

jobs := make(chan int, 100)
results := make(chan int, 100)

for w := 1; w <= 3; w++ {           // 3 workers, however many jobs
    go worker(w, jobs, results)
}
for j := 1; j <= 9; j++ {
    jobs <- j
}
close(jobs)   // signals workers to stop once drained

Pipeline: chaining stages with channels

Each stage is a function that takes an input channel and returns an output channel, run as its own goroutine — data flows through the pipeline one stage at a time, and each stage can start on later items before earlier ones finish downstream.

Gopipeline.go
func generate(nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for _, n := range nums {
            out <- n
        }
    }()
    return out
}

func square(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            out <- n * n
        }
    }()
    return out
}

for result := range square(generate(1, 2, 3, 4)) {
    fmt.Println(result)   // 1, 4, 9, 16
}

Fan-out, fan-in

Fan-out means multiple goroutines reading from the same channel to parallelize work (as the worker pool does above); fan-in is the reverse — merging several channels into one, typically with a helper that launches a goroutine per input channel, each forwarding to a shared output channel, closed via a sync.WaitGroup once all inputs are drained.

Sources

1
The Go Authors. "Go Concurrency Patterns: Pipelines and cancellation", go.dev/blog/pipelines.