https://free-engineer.life/golang-select/
select文はチャネルの送受信操作を多重化できる。
select文の書き方は、switch文に似ている。
select {
case <-ch1:
// ch1から受信したときに実行される処理
case v := <-c2:
// ch2から受信したときに実行される処理
// 変数に値を入れることもできる
case ch3 <- y:
// ch3に送信したときに実行される処理
default:
// どのcaseも準備できていないときに実行される処理(省略可能)
}
ポイントは、「select文は上から順番に評価されない」こと。
チャネルへの送受信は実行可能かを判断して、可能であれば実行される。
つまり、送信の場合は「キャパシティ(バッファ)がいっぱいになっていないか」、受信の場合は、「チャネルに値が送信されたか、チャネルが閉じられたか」を確認し、処理を進める準備が出来ていれば実行される。
もし、どのチャネルも準備が出来ていなければ、defaultが実行される。もしdefaultを省略していたらselect文全体がブロックされる。
複数のcaseが実行可能な状況だった場合、どれか1つのcaseがランダムに実行される。
defaultを省略した状態でselect文がブロックされるのを確認する。
package main
import (
"fmt"
"time"
)
func main() {
start := time.Now()
ch := make(chan struct{})
go func() {
time.Sleep(5 * time.Second)
close(ch)
}()
fmt.Println("Selectブロック中")
select {
case <-ch:
fmt.Printf("ch1 close. ブロック時間: %v\\n", time.Since(start))
}
}
実行結果は
$ go run main.go
Selectブロック中
ch1 close. ブロック時間: 5.005249353s
すべてのcase文が準備が整っていない場合、default節が実行される。
package main
import "fmt"
func main() {
ch1 := make(chan struct{})
ch2 := make(chan struct{})
// ch1, ch2ともに宣言しただけで、何も送信されてこない(受信することはない)
// そのため、default節が実行される
select {
case <-ch1:
fmt.Println("ch1")
case <-ch2:
fmt.Println("ch2")
default:
fmt.Println("default")
}
}
実行結果は