channel lock
channel でブロックするようなコードが書ける。例えばスレッドの並列数を制限したいとか、そういう簡単な用途で使うのに取り回しがいい。
package main import ( "fmt" "time" ) func main() { go func() { for { fmt.Printf(".") time.Sleep(100 * time.Millisecond) } }() queue := make(chan int, 3) time.Sleep(1 * time.Second) queue <- 1 fmt.Println(1) time.Sleep(1 * time.Second) queue <- 2 fmt.Println(2) time.Sleep(1 * time.Second) queue <- 3 fmt.Println(3) go func() { time.Sleep(3 * time.Second) <-queue }() time.Sleep(1 * time.Second) // Lock queue <- 4 fmt.Println(4) }
0.1 秒毎に .
が出力されて、 1 秒ごとに 1,2,3 と出力していく。queue
は3つまで許容するので、4つめの Lock
のところで queue
に 4 が送信できなくてロックする。その上にある goroutine で 3 秒後に queue
から 1 つ受信して捨てると、 4 が送信できるようになって動く。
出力はこんな感じになる
..........1 ..........2 ..........3 ..............................4
4 のときだけ 3 秒ロックしてるのがわかる。ところでこの queue
から受信するコードをなくすとどうだろう。ついでに邪魔だから .
を出力していた goroutine もなくしてしまおう。
package main import ( "fmt" "time" ) func main() { queue := make(chan int, 3) time.Sleep(1 * time.Second) queue <- 1 fmt.Println(1) time.Sleep(1 * time.Second) queue <- 2 fmt.Println(2) time.Sleep(1 * time.Second) queue <- 3 fmt.Println(3) time.Sleep(1 * time.Second) queue <- 4 fmt.Println(4) }
例外が出る。
1 2 3 fatal error: all goroutines are asleep - deadlock! goroutine 1 [chan send]: main.main() /Users/rosylilly/tmp/go_channel_test/main.go:24 +0x22e exit status 2
全部の goroutine が 寝てて、何もしてないからデッドロック状態だ、ということらしい。デッドロック検知して自分で死ぬ。モダンな感じだ。