A channel is Go’s conduit for passing values between goroutines. Sending and receiving messages lets goroutines communicate and synchronize, making data flow explicit instead of relying on a global shared state. Think of a channel as a network cable or UNIX pipe connecting concurrent tasks. section 1.4 section 1.4.3
Use channels when goroutines need to pass data, distribute work, or report results. A send or receive pauses participating goroutines so they synchronize around the message. This supports a design of focused sequential stages, each receiving data, doing work, and forwarding the next value. section 1.4.3 section 6.6.1
Figure 1.5 Goroutines that are running concurrently communicate over channels. These goroutines forward the message to the next goroutine. Each goroutine performs some computation on the received message before sending it to the next one.
A pipeline makes channel flow visible: each goroutine receives a message, performs a computation, and forwards it to the next stage. section 1.4.3
Channels fit especially well in concurrent pipelines:
- Connect independent producer, processing, and consumer stages with message flow. section 6.6.1
- Keep stages flexible: stages can be added or removed without changing their internal code. section 6.6.1
- Close an output channel only after all senders finish, so receivers know no more values will arrive. section 6.9
- Let receivers stop listening when closure signals that a result stream has ended. section 6.9
Reporting concurrent HTTP results
A dispatcher can start worker goroutines that send HTTP requests, process responses, and deliver Result values through an output channel. A monitoring goroutine closes that channel after every worker finishes; closing earlier risks a worker sending to a closed channel and causing a panic. section 6.9
Channels coordinate goroutines; they do not make shared memory safe. Goroutines still share one memory space, so passing a message does not itself protect shared data. For straightforward protection of a shared map, counter, cache, or similar state, a mutex is usually simpler and more efficient than routing state access through channels. section 1.4.3 section 8.2.4
Avoid treating channels as the answer to every concurrent problem. Prefer them for communication and task coordination; prefer classical synchronization when direct shared-state protection is the simpler design. Buffered channels can also be used to limit concurrency in request dispatching. section 1.4.3 section 6.10









