channel にはバッファという物が設定出来ます。いわゆるキューのサイズです。これが未指定の場合だと1つ入れるだけでバッファがいっぱいになります。バッファがいっぱいの状態でさらに送信しようとするとバッファが溢れて deadlock の panic が発生します。同じように誰も書かない channel を読み取ろうとした場合にも deadlock は発生します。
Go のランタイムはこのとき groutine の存在を確認します。別の goroutine が起動している時は「その channel を読み書きする可能性がある」という事で deadlock を免れます。
goroutine が書き込まないケース
go
1package main
2
3import (
4 "time"
5)
6
7func listenChannel(message chan string) {
8 time.Sleep(5 * time.Second)
9 //message <- "Hello"
10}
11
12func main() {
13 message := make(chan string)
14 go listenChannel(message)
15 println(<-message)
16}
https://play.golang.org/p/zbmMC7tWwW
例えばこのコードは5秒後に deadlock が起きます。listenChannel が終了してしまうと goroutine は1つ(main)だけになり、message を待っているのに message を書きこむ groutine が無くなってしまうので deadlock を起こすという事です。この時、message に既に何か詰まっていれば groutine が終了したとしても、(goroutine の存在を確認する必要がないのですから) deadlock を起こす事はありません。
go
1package main
2
3import (
4 "time"
5)
6
7func listenChannel(message chan string) {
8 time.Sleep(5 * time.Second)
9 //message <- "Hello"
10}
11
12func main() {
13 message := make(chan string, 2)
14 message <- "Wow"
15 go listenChannel(message)
16 println(<-message)
17}
https://play.golang.org/p/DjBCUW9o0P
このコードは直ぐに終了します。
main が読み取らないケース
逆に main 側が読み取らない場合を見て下さい。
go
1package main
2
3import (
4 "time"
5)
6
7func listenChannel(message chan string) {
8 message <- "Hello"
9}
10
11func main() {
12 message := make(chan string)
13 go listenChannel(message)
14 time.Sleep(5 * time.Second)
15 //println(<-message)
16}
https://play.golang.org/p/iCgLTs3va4
この場合、5秒後には gouroutine が消えますが main は生きているので channel を読み取る可能性があるという事で deadlock は起きません。