Concurrency · 3 MIN READ

The sender closes, the receiver ranges

Decide who closes a channel, and why the other side must not.

Closing a channel says that no more values will be sent. Give that decision to the producer, or to a coordinator that knows all producers have finished. A receiver should not close a stream while senders may still use it.

Receivers can drain a closed buffered channel. v, ok := <-ch reports false only when the channel is closed and empty; for v := range ch then ends. Sending after close and closing twice both panic.

SEE THE IDEA

The sender announces that no more values are coming

  1. 01

    Produce

    go
    ch <- value

    Send every value first

  2. 02

    Finish

    go
    close(ch)

    Signal the end of production

  3. 03

    Drain

    go
    for v := range ch

    Read remaining values, then stop

Close is a statement about the stream ending, not about discarding its queued values.

In practice

Give exactly one owner responsibility for closing. If multiple workers send, a coordinator can wait for all of them and close the results channel afterward. Receivers normally do not close because they cannot know that every sender has finished.

Watch out

Sending to a closed channel or closing it twice panics. A channel used only for coordination does not always need to be closed.

Official reference ↗

Work through the exercise

go
package main

// squares should send each square and then let the consumer's range
// loop finish on its own.
func squares(n int) <-chan int {
	out := make(chan int)
	go func() {
		for i := 1; i <= n; i++ {
			out <- i * i
		}
	}()
	return out
}

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.