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