Tutorials Logic, IN info@tutorialslogic.com

Golang Channels: Communicate Between Goroutines Safely

Unbuffered and Buffered Channels

Go channels synchronize goroutines while transferring typed values. Sending or receiving may block, so channel ownership, closure, buffering, cancellation, and the number of participants must be designed together.

An unbuffered send completes only when a receiver is ready, creating a synchronization point. A buffered channel allows sends until capacity is full and receives until it is empty. Buffering absorbs a bounded mismatch; it does not remove the need for backpressure or cancellation.

Closing and Ownership

The goroutine that knows no more values will be sent should close the channel. Receivers normally do not close it, and a channel does not need closing merely to release memory. Sending to a closed channel panics; receiving returns queued values and then the zero value with ok false.

Range over a channel ends only after closure, so an unclosed producer can leave consumers blocked forever. Nil channels block forever on send and receive and can be enabled or disabled deliberately inside select.

select, Cancellation, and Timeouts

select waits until one communication case can proceed. Include context cancellation for request-scoped work and ensure every worker can stop even when downstream consumers leave. A default case makes select non-blocking and can create busy loops if used without pacing.

Use timers carefully and stop or reuse them in repeated loops. Timeouts are failure policy, not a substitute for fixing leaked goroutines or an unbounded workload.

Worker and Pipeline Boundaries

A worker pool needs a bounded job source, defined result collection, cancellation, and a WaitGroup or equivalent completion rule. Close result channels only after every producer finishes. In pipelines, each stage must stop sending when the next stage cancels, or blocked sends leak goroutines.

Cancelable Worker

Cancelable Worker
func worker(ctx context.Context, jobs <-chan int, results chan<- int) {
          for {
              select {
              case <-ctx.Done():
                  return
              case job, ok := <-jobs:
                  if !ok {
                      return
                  }
                  select {
                  case results <- job * job:
                  case <-ctx.Done():
                      return
                  }
              }
          }
      }

Receive Until Closed

Receive Until Closed
values := make(chan int, 2)
      values <- 10
      values <- 20
      close(values)

      for value := range values {
          fmt.Println(value)
      }
Before you move on

Golang Channels: Communicate Between Goroutines Safely Mastery Check

6 checks
  • The sender owns closure.
  • Every blocking operation has a completion or cancellation path.
  • Buffer capacity has an operational reason.
  • Closed receives and zero values are distinguished with ok.
  • Results close only after all producers finish.
  • Tests include cancellation, early consumer exit, and race detection.

Go Channels Questions Learners Ask

No. Close only when receivers need a no-more-values signal. Garbage collection does not require explicit channel closure.

Yes, but one coordinator must determine when all senders are finished before closing the channel.

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.