Go言語のゴルーチンとチャネルを見て来ていますが、これまでは主にチャネルを1つだけ使う処理を扱っていました。
ここでは、複数のチャネルを使った処理を見ていきます。そこで出てくるのがselect文になります。
ここでは、そのselectを使ったコードを見ていきましょう。
select
select文を使うことで、ゴルーチンは複数の操作を待機することができます。
selectは、ケースの1つが実行可能になるまで他のケースをブロックし、その後に他ケースを実行します。複数のケースが準備ができている場合はランダムに1つを選択して順に処理して行きます。
select文はswitch文の形に似た方法で処理します。
次のコードでやってみましょう。
package main
import (
"fmt"
"time"
)
func sendSum(s []int, sum chan int) {
sumValue := 0
time.Sleep(3000 * time.Millisecond)
for _, v := range s {
sumValue += v
}
sum <- sumValue
}
func sendValue(even, odd chan<- int, quit chan<- bool) {
for i := 0; i < 10; i++ {
time.Sleep(500 * time.Millisecond)
if i%2 == 0 {
even <- i
} else {
odd <- i
}
}
quit <- true
}
func receiveValue(sum, even, odd <-chan int, quit <-chan bool) {
for {
select {
case v := <-sum:
fmt.Println("sumチャネルからの値:", v)
case v := <-even:
fmt.Println("evenチャネルからの値:", v)
case v := <-odd:
fmt.Println("oddチャネルからの値:", v)
case <-quit:
return
}
}
}
func main() {
s := []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
sum := make(chan int)
even := make(chan int)
odd := make(chan int)
quit := make(chan bool)
go sendSum(s, sum)
go sendValue(even, odd, quit)
receiveValue(sum, even, odd, quit)
fmt.Println("処理終了")
}
sendSum()、sendValue()、receiveValue()という3つの関数を定義しています。
順に、スライスの値の合計値をチャネルに渡す処理、0から9までの値をループで回して偶数/奇数に分けてそれぞれの値を別々のチャネルに渡す処理、それぞれ受けたチャネルの値をselet文で処理して出力する処理、ということになっています。
sendValue()は、終了を示すために quit <- true としています。
receiveValue()は、for文で受け取ったチャネルを1つずつ取り出してselect文でそれぞれのcase判定をして、どのチャネルからの値かを出力しています。
main()の中で、スライスと各チャネルを定義し、それぞれの関数に引数として渡しています。sendSum()、sendValue()をゴルーチンで処理しています。最後の処理の終了を出力しています。
実行すると、次のように出力されます。
evenチャネルからの値: 0
oddチャネルからの値: 1
evenチャネルからの値: 2
oddチャネルからの値: 3
evenチャネルからの値: 4
sumチャネルからの値: 55
oddチャネルからの値: 5
evenチャネルからの値: 6
oddチャネルからの値: 7
evenチャネルからの値: 8
oddチャネルからの値: 9
処理終了
sendSum()は3秒後に実行、sendValue()は0.5秒毎に実行するようにtime.Sleep()を使っているので、上から順番に0.5秒ごとに出力され、sumチャンネルの値が遅れて途中で出力されます。
それぞれの値が、それぞれに該当するチャネルから値を受け取って出力されているのがわかります。
このように、複数のチャンネルから選択して処理するのがselect文になります。
最後に
ここでは、Go言語のselect文を扱いました。
select文を使うことで、ゴルーチンは複数の操作を待機することができます。それによって、複数のチャネルを使った処理を行うことができます。
select文はswitch文のcaseの処理に似た方法でそれぞれのチャネルを判定して処理します。