select

select 文を使うと、複数のゴルーチンとの通信を選択的に処理することができる。
次の例では、main 関数で起動された3つのゴルーチンからの通信を for ループの中で select 文を使って待ち受けている。もし、どれかのゴルーチンから通信を受信すれば、受信したデータを出力して次のループに移る。どれからも受信できなければ default 節が実行されて "None" を出力し、250 ミリ秒待った後に次のループに移る。
各ゴルーチンは終了するときに専用のチャネル quit を使ってデータ(この例では 0 を使っているけど何でもいい。単に終了の通知をするだけなので。)を送ってくるので、全部のゴルーチンが終了したら for ループも終了する。

package main

import (
    "fmt"
    "strconv"
    "time"
)

func test1(n int, ch, quit chan<- int) {
    for ; n > 0; n-- {
        ch <- n time.Sleep(500 * time.Millisecond)
    }
    quit <- 0
}

func test2(n int, ch chan<- float64, quit chan<- int) {
    for ; n > 0; n-- {
        ch <- float64(n) / 10.0 time.Sleep(250 * time.Millisecond)
    }
    quit <- 0
}

func test3(n int, ch chan<- string, quit chan<- int) {
    for ; n > 0; n-- {
        ch <- strconv.Itoa(n * 10) time.Sleep(750 * time.Millisecond)
    }
    quit <- 0
}

func main() {
    ch1 := make(chan int)
    ch2 := make(chan float64)
    ch3 := make(chan string)
    quit := make(chan int)

    go test1(6, ch1, quit)
    go test2(8, ch2, quit)
    go test3(4, ch3, quit)
    for n := 3; n > 0; {
        select {
            case c := <- ch1: fmt.Println(c)
            case c := <- ch2: fmt.Println(c)
            case c := <- ch3: fmt.Println(c)
            case <- quit: n--
            default: fmt.Println("None") time.Sleep(250 * time.Millisecond)
        }
    }
}
^o^ > go run channel_select.go
6
40
0.8
None
0.7
None
5
0.6
None
0.5
30
None
4
0.4
None
0.3
None
20
3
0.2
None
0.1
None
2
None
10
None
1
None
None

うまくいったようだ。