チャネルを使ってゴルーチンの同期をとることができる。
次のコードを見てほしい。
package main import ( "fmt" "time" ) func makeRoutine(code string, in <-chan int) chan int { out := make(chan int) go func() { for { <- in fmt.Print(code) time.Sleep(200 * time.Millisecond) out <- 0 } }() return out } func main() { ch1 := make(chan int) ch2 := makeRoutine("h", ch1) ch3 := makeRoutine("e", ch2) ch4 := makeRoutine("y", ch3) ch5 := makeRoutine("!", ch4) ch6 := makeRoutine(" ", ch5) for i := 0; i < 10; i++ { ch1 <- 0 <- ch6 } }
makeRoutine
関数は、文字列 code
とチャネル in
を引数にとる。まずチャネル out
を作っておいて、無名関数をゴルーチンで起動、最後に out
を返している。無名関数は無限ループになっていて、in
から何か送信されてくるのを待って code
を出力し、200 ミリ秒待ってから out
にデータを送信する。
main
関数では、最初の(送信用)チャネル ch1
を作り、makeRoutine
関数に渡している。返ってきたチャネルは、次の makeRoutine
関数に渡され、返ってきたチャネルはさらに次の makeRoutine
関数に渡される。こうして5つの makeRoutine
関数の中のゴルーチンがチャネルを通じて数珠つなぎのようになる。これらのゴルーチンは、最初のチャネル ch1
にデータを送信することによって動作を開始し、最後のチャネル(main
関数から見ると ch6
)にデータを送信して終わる。これを10回繰り返している。
実行してみよう。
^o^ > go run go_hey.go hey! hey! hey! hey! hey! hey! hey! hey! hey! hey!
この実行例ではわからないけど、1文字ずつ時間を空けて hey! の文字列が10回出力されている。各ゴルーチンは1文字出力するだけなので、うまく同期して動作している様子がわかる。