HowtoGo
Home / Concurrency / Channels

A channel is a typed pipe for sending values between goroutines. make(chan T) creates one; the send and receive on either end are how goroutines synchronize.

make(chan string) creates an unbuffered channel. A send blocks until another goroutine receives, and a receive blocks until another goroutine sends — the exchange itself is the synchronization.

ch := make(chan string)

go func() {
    ch <- "done"
}()

msg := <-ch
fmt.Println(msg) // done

A buffered channel holds a fixed number of values with no receiver waiting. make(chan int, 2) holds two; a send only blocks once the buffer is full.

ch := make(chan int, 2)
ch <- 1
ch <- 2
fmt.Println(<-ch, <-ch) // 1 2

Channel operations

OperationBehavior
make(chan T)Unbuffered channel of type T.
make(chan T, n)Buffered channel with capacity n.
ch <- vSends v. Blocks if the buffer is full (or always, if unbuffered).
v := <-chReceives a value. Blocks until one is available.
v, ok := <-chok is false once ch is closed and drained.
close(ch)Marks ch closed. Sending on it afterward panics.
len(ch) / cap(ch)Values currently buffered, and the buffer's total capacity.
for v := range chReceives repeatedly until ch is closed.

Closing and direction

close(ch) marks a channel as done. range over a channel receives values until it's closed, then exits the loop on its own. Close after the last send, never before, or buffered values are lost.

ch := make(chan int, 3)
ch <- 1
ch <- 2
close(ch)

for v := range ch {
    fmt.Println(v)
}
// 1
// 2

chan<- int accepts sends only, <-chan int accepts receives only. A bidirectional channel converts automatically when passed into either parameter, and the compiler then blocks the wrong direction inside that function.

func producer(out chan<- int) {
    out <- 42
}

func consumer(in <-chan int) {
    fmt.Println(<-in)
}

ch := make(chan int)
go producer(ch)
consumer(ch) // 42

The buffered example, the closed-channel range, and the directional producer all run as one program: two buffered values print first, then the producer's value.

Terminal
$ go run channels.go
1
2
42