Go Concurrency Patterns (Deep Dive)
Lesson, slides, and applied problem sets.
View SlidesLesson
Go Concurrency Patterns (Deep Dive)
This module is a practical concurrency playbook with an emphasis on correctness under load.
1) Structured concurrency
A goroutine should have:
- an owner,
- a startup reason,
- and a shutdown path.
Prefer:
contexttrees,errgroupor explicit parent coordination,- and bounded, joinable fan-out.
Fire-and-forget without ownership is a leak risk.
2) Cancellation you can trust
Cancellation must be observed, not declared.
Use these checks:
select { case ...: case <-ctx.Done(): return ctx.Err() }- include
ctx.Done()in blocking operations, - ensure blocked producers and consumers stop when context is canceled.
3) Backpressure and bounded parallelism
Backpressure keeps latency stable.
- use bounded queues,
- use bounded worker pools,
- and limit in-flight work when downstream cannot keep up.
Load shedding (default case path) is better than unbounded memory growth.
4) Worker pools and lifecycle
Common mistakes:
- letting multiple goroutines close the same channel,
- forgetting to drain or cancel on shutdown,
- over-fine lock contention for tiny units.
Rules:
- producer closes
jobs, - single owner closes
results, - one goroutine should drive lifecycle transitions.
5) Safe publication and data flow
Shared mutable state needs synchronization.
- channel close for event boundaries,
- mutex for critical sections,
- atomic snapshots for read-heavy configs.
6) Testing concurrency
- include -race,
- include cancellation tests,
- include ordering tests when results depend on index,
- include bounded concurrency tests with deterministic counters.
7) Lab: Bounded map
The associated practice question (bound-map) asks for order-preserving execution with strict concurrency limits.
Pass criteria:
- output order matches input order,
- concurrency cap is enforced,
- function tolerates empty / degenerate inputs.