バッファ付きチャネルをcloseするとどうなるか
突然ですが、次のプログラムを動かした時の出力を答えてください。
package main
import "fmt"
func main() {
// バッファ 2 のチャネル
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)
for n := range ch {
fmt.Println(n)
}
}
正解はこちら
https://play.golang.org/p/mDvIj--7zC
1
2
Program exited.
先にcloseされていますが、バッファに残っている値はすべてちゃんと読みだしてからcloseを判断しているようです。
チャネルの受信側には、すべての値が読み出されてから close 通知がくる
次のプログラムを動かして見ましょう
package main
import "fmt"
func main() {
// バッファ 3 のチャネル
ch := make(chan int, 3)
ch <- 1
ch <- 2
close(ch)
n1, ok1 := <- ch
n2, ok2 := <- ch
_, ok3 := <- ch
fmt.Println(n1, ok1)
fmt.Println(n2, ok2)
fmt.Println(ok3)
}
1 true
2 true
false
送信側からは、closeしたチャネルには値を送信できません
package main
func main() {
// バッファ 3 のチャネル
ch := make(chan int, 3)
ch <- 1
ch <- 2
close(ch)
ch <- 3
}
panic: send on closed channel
goroutine 1 [running]:
main.main()
/tmp/sandbox997235944/main.go:10 +0x120
送信側は、チャネルがバッファ付きだろうがなかろうが、データを送りきってからcloseすれば良いわけです。
close するタイミングと、受信側でcloseされたと判断されるタイミングに時差があるので、結果的には直感的ですが、ちょっと戸惑う挙動かと思います。
あまり言及している記事がなかった記憶があるので、知っているとproducer-consumer パターンの実装の時に役立ちます。