Problems with Go channels (2016)

State of Go Channels and CSP Usage

  • Many commenters say the 2016 criticisms still hold: the language and channel semantics haven’t changed meaningfully.
  • Broad consensus that channels were overhyped early on; experienced Go devs now treat them as a sharp, specialized tool, not a default primitive.
  • Some report successful CSP-style systems, but only in tightly controlled topologies with good design docs and few developers.

Main Problems Identified

  • Lifecycle and shutdown: coordinating when to close shared channels and tear down goroutines is error‑prone, especially with multiple producers.
  • Deadlocks and “dead goroutines”: hard to reason about when everything is wired via channels; control flow becomes a hidden graph rather than stack calls.
  • API design: using channels in exported interfaces is widely discouraged; it leaks concurrency concerns and makes mocking/maintenance harder.
  • Semantics: close, nil channels, and range over channels are seen as inconsistent or “cray-cray,” leading to subtle bugs.
  • CSP purity (channels for everything) usually degenerates into ad‑hoc “shutdown” channels and complex cancellation logic.

Suggested Best Practices and Alternatives

  • Prefer mutexes, atomics, and sync.WaitGroup/errgroup for shared state or coordination; use channels mainly for signaling and simple work queues.
  • Hide channels inside modules; expose synchronous APIs instead.
  • Rule of thumb: writer owns close, but multi-writer channels make this hard; many recommend avoiding that pattern entirely.
  • Use context.Context or explicit counters/flags for cancellation and lifecycle management instead of elaborate channel schemes.

Performance and Buffering

  • Disagreement over performance: some claim channels are slower because they use mutexes; others show benchmarks where channels beat sync.Mutex under heavy contention.
  • Buffered channels are called a major footgun: they remain blocking and large buffers are often a misguided “optimization” that masks deadlocks.

Comparisons and Meta‑Discussion

  • Several compare Go’s channels unfavorably with Erlang/Elixir (unbounded queues, supervision) and Rust async channels (no “dead goroutine” GC issues).
  • Broader critique: Go’s design is seen by some as simplistic and dismissive of PL expertise; others argue its simplicity and success in real systems vindicate the choices.