Concurrency · 3 MIN READ

A buffer is a mailbox, not a meeting

Send n values on a channel of capacity n without another goroutine.

The Tour's "Buffered Channels" page: make(chan int, 100) sends without a receiver until the buffer is full, and receives without a sender until it is empty. An unbuffered channel is a rendezvous. A buffered one is a mailbox of a known size.

The deadlock people then write is filling a buffer of 1 with two sends from the only goroutine there is. The buffer does not make the channel unbounded. It makes the bound visible in the make.

SEE THE IDEA

A channel buffer has a finite number of slots

  1. 01

    Space available

    go
    make(chan int, 2)

    Two sends may queue without receivers

  2. 02

    Buffer full

    go
    ch <- next

    The sender waits for space

  3. 03

    Receive

    go
    v := <-ch

    Frees one queued slot

Buffering changes when a send blocks; it does not remove synchronization requirements.

In practice

Choose capacity to express the intended amount of queued work. A small buffer can smooth bursts and decouple short timing differences. It cannot fix a missing receiver or an endless producer; once capacity is exhausted, backpressure still reaches the sender.

Watch out

len(ch) is a momentary queue size, not a reliable precondition for a future send or receive.

Official reference ↗

Work through the exercise

go
package main

// Fill sends 0..n-1 on a channel of capacity n, closes it, and
// returns what a range reads back. It must not start a goroutine.
func Fill(n int) []int {
	return nil
}

func main() {}
Try it yourself

Trace each value and write down your reasoning. Copy the source into GopherForge or your local Go environment to compile and check it. This web page does not execute your code or send it to a compiler service.

Progress stays in this browser. No account needed.