Channel Types

Unbuffered Channels

Unbuffered channels have no capacity to store values. When you send a value on an unbuffered channel, the operation will block until another goroutine is ready to receive the value.

ch := make(chan int)  // Unbuffered channel

// In goroutine 1
ch <- 42  // Blocks until goroutine 2 receives

// In goroutine 2
value := <-ch  // Blocks until goroutine 1 sends

This creates a synchronization point between goroutines, ensuring that the sending goroutine and receiving goroutine are synchronized.

Buffered Channels

Buffered channels have a capacity to store a limited number of values. Sending to a buffered channel only blocks when the buffer is full, and receiving only blocks when the buffer is empty.

ch := make(chan int, 3)  // Buffered channel with capacity 3

ch <- 1  // Doesn't block
ch <- 2  // Doesn't block
ch <- 3  // Doesn't block
ch <- 4  // Blocks until someone receives from the channel

When to Use Each Type

  • Unbuffered channels are best when you want a guarantee that data has been received by another goroutine (synchronization)
  • Buffered channels are useful when:
    • You want to decouple the sender and receiver temporally
    • You know the approximate number of values that will be sent
    • You want to batch process items
    • You’re dealing with bursty data and want to smooth out processing

Comparison of Channel Types

FeatureUnbuffered ChannelsBuffered Channels
Creationmake(chan T)make(chan T, size)
Capacity0Specified size
Send blocks whenAlways (until received)Buffer is full
Receive blocks whenAlways (until sent)Buffer is empty
SynchronizationStrong (rendezvous)Weaker (queue)
Use caseDirect handoff, strict synchronizationDecoupling, batching, rate limiting