Go channel系列:html
當未爲channel分配內存時,channel就是nil channel,例如var ch1 chan int。nil channel會永遠阻塞對該channel的讀、寫操做。code
nil channel會阻塞對該channel的全部讀、寫。因此,能夠將某個channel設置爲nil,進行強制阻塞,對於select分支來講,就是強制禁用此分支。htm
如下是一個nil channel的示例:blog
package main import ( "fmt" "math/rand" "time" ) // 不斷向channel c中發送[0,10)的隨機數 func send(c chan int) { for { c <- rand.Intn(10) } } func add(c chan int) { sum := 0 // 1秒後,將向t.C通道發送時間點,使其可讀 t := time.NewTimer(1 * time.Second) for { // 一秒內,將一直選擇第一個case // 一秒後,t.C可讀,將選擇第二個case // c變成nil channel後,兩個case分支都將一直阻塞 select { case input := <-c: // 不斷讀取c中的隨機數據進行加總 sum = sum + input case <-t.C: c = nil fmt.Println(sum) } } } func main() { c := make(chan int) go add(c) go send(c) // 給3秒時間讓前兩個goroutine有足夠時間運行 time.Sleep(3 * time.Second) }
上面的示例中,send()向通道c不斷髮送10之內的隨機整數,add()則在一秒內不斷讀取通道c中的數據並進行加總。一秒時間到後,t.C通道就會有數據,第二個case分支就會被選中,第二個case會讓第一個case評估的channel變爲nil channel,使得第一個case今後永久禁用,由於第二個case沒有多餘的數據可讀,它也被永久禁用。總共3秒以後,main goroutine結束,程序結束。內存
若是不理解NewTimer(d),換成After(d)是同樣的,After(d)和NewTime(d).C是等價的。get
func add(c chan int) { sum := 0 t := time.After(1 * time.Second) for { select { case val := <-c: sum = sum + val case <-t: c = nil fmt.Println(sum) } } }