Updated at 2022-04-19 03:05

Channels can be viewed as a FIFO (first in, first out) message queues. Channels are used to transfer values, or more accurately, transfer ownerships of values, between goroutines.

You create channels with make. The zero values of channel types is nil.

c := make(chan int, 10)
// chan int  = channel type (channel of integers here)
// 10        = value buffer capacity, can be omitted for unbuffered channels

A channel with zero capacity is called unbuffered channel and a channel with non-zero capacity is called buffered channel.

Common channel operations:

ch <- v         // send value v to channel ch
v, ok = <-ch    // receive value v, and "ok" becomes false if the channel is closed
cap(ch)         // returns value buffer capacity
len(ch)         // returns number of values currently in value buffer
close(ch)       // closing a channel, closing nil or already closed channel will panic
  • close() on a nil channel will panic.
  • ch <- v on a nil channel will block forever.
  • v, ok = <-ch on a nil channel will block forever.

You usually use channels with for and select statements:

for v = range ch {
    // waits for `v` values until the channel is closed

select is useful for listening multiple channels:

package main

import (

func main() {
    greetings := make(chan string)
    names := make(chan string)
    go func() {
        greetings <- "hello"
        time.Sleep(1 * time.Second)
        greetings <- "hi!"
        time.Sleep(1 * time.Second)
    go func() {
        names <- "John"
        time.Sleep(1 * time.Second)
        names <- "Bob"
        time.Sleep(2 * time.Second)
    for {
        select {
        case g, ok := <-greetings:
            if !ok {
                break LOOP
        case n, ok := <-names:
            if !ok {
                break LOOP