Concurrency: Channels - kyunghoj/golang GitHub Wiki

Channels

Channels provide a way for two goroutines to communicate with each other and synchronize their execution. Here is an example program using channels:

package main

import (
    "fmt"
    "time"
)

func pinger(c chan string) {
    for i := 0; ; i++ {
        c <- "ping"
    }
}

func printer(c chan string) {
    for {
        msg := <- c
        fmt.Println(msg)
        time.Sleep(time.Second * 1)
    }
}

func main() {
    var c chan string = make(chan string)

    go pinger(c)
    go printer(c)

    var input string
    fmt.Scanln(&input)
}

Channel Direction

We can specify a direction on a channel type, thus restricting it to either sending or receiving. For example, pinger's function signature can be changed to this:

func pinger(c chan<- string)

Now pinger is only allowed to send to c. Similarly, we can change printer to this:

func printer(c<-chan string)

A channel that doesn't have these restrictions is known as bidirectional.

Select

select picks the first channel that is ready and receives from it (or sends to it). If more than one of the channels are ready, then it randomly picks which one to receive from. If none of the channels are ready, the statement blocks until one becomes available.

The select statement is often used to implement a timeout:

select {
case msg1 := <- c1:
    fmt.Println("Message 1", msg1)
case msg2 := <- c2:
    fmt.Println("Message 2", msg2)
case <- time.After(time.Second):
    fmt.Println("timeout")
}

Buffered Channel

It's also possible to pass a second parameter to the make function when creating a channel:

c := make(chan int, 1)

This creates a buffered channel with a capacity of 1. Normally, channels are synchronous; both sides of the channel will wait until the other side is ready. A buffered channel is asynchronous; sending or receiving a message will not wait unless the channel is already full, then sending will wait until there is room for at least one more int.