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
うまくいったようだ。