Goでの特徴的な機能の一つであるgoルーチンですが、その終了判定あるいはチャネルの選択時の一つのパターンがdoneパターンと言われるもの。
コードのベースは以下からですが、
https://github.com/mushahiroyuki/lgo/blob/main/example/ch10/ex1009.go
実はチャネルサイズが10なので、以下のgoルーチンのループでは11以降はチャネルへの書き込みができないので待ちになります。実質はmainルーチンが終了するとgoルーチンも終了されるので処理上の問題はないのですが、
ここでgoルーチン側で終了待ちをするためのdoneパターンを導入してみます。
close(done)がgoルーチンへの終了シグナルになりますが、goルーチン側ではselect/caseを使っています。チャネルの処理が継続できる条件が複数あるときに、継続可能となった処理をselect/caseで選択して実行するものです。select/case文の特徴的なところは、複数の条件が成立しているときにはランダムで継続可能処理を選ぶことでswitch文のように上から順番のような優先順位はつけないということです。
func main() {
ch := make(chan int)
var result []int
done := make(chan struct{})
go func() { // 処理してもらう数値をchに入れる
for i := 0; i < 100; i++ {
select {
case <- done:
fmt.Print(". ")
return
case ch <- i:
}
}
}()
result = processChannel(ch)
close(done)
time.Sleep(1000)
fmt.Printf("result: %d\n", result)
}
このサンプルでは確実にdone処理を実行するためにmainルーチンで1000nsの待ち時間を入れています。
実行すると、例えば以下のようになります。
ゴルーチン 起動完了
process: 0 0 0
process: 9 81 0
process: 5 25 2
process: 6 36 2
process: 4 16 0
process: 7 49 1
process: 1 1 2
process: 8 64 2
process: 2 4 1
process: 3 9 1
. result: [0 81 16 9 4 49 64 25 1 36]
admin