注:該文原文爲 Channel Axioms ,做者是 Dave Cheney,這是他的博客地址程序員
大部分的新的 Go 程序員能快速理解 channel 是做爲一個 queue 的值和認同當 channel 是滿的或者是空的時候, 操做是阻塞的概念。golang
這篇文章探討了 channel 四個不太常見的特性:c#
這第一個例子對於新來者是有點小驚奇的,它給一個 nil channel 發送數據,形成永遠阻塞。函數
如下這個程序將在第5行形成死鎖,由於未初始化的 channel 是 nil 的,其值是零.net
package main func main() { var c chan string c <- "let's get started" // deadlock }
點擊這裏運行code
相似的,從一個 nil channel 接收數據,會形成接受者永遠阻塞。blog
package main import "fmt" func main() { var c chan string fmt.Println(<-c) // deadlock }
點擊這裏運行ip
爲何會發生這樣的狀況?下面是一個可能的解釋get
如下程序將有可能 panic,由於在它的兄弟姐妹有時間完成發送他們的值以前,這第一個 goroutine 在達到10的時候將關閉 channel。博客
package main import "fmt" func main() { var c = make(chan int, 100) for i := 0; i < 10; i++ { go func() { for j := 0; j < 10; j++ { c <- j } close(c) }() } for i := range c { fmt.Println(i) } }
點擊這裏運行
所以爲何沒有一個 close() 版本能讓你檢測 channel 是否關閉?
if !isClosed(c) { // c isn't closed, send the value c <- v }
可是這個函數有一個內在的競爭,某我的可能在咱們檢查完 isClosed(c) 以後,可是代碼獲取 c <- v 以前關閉這個 channel。
處理這個問題的方法在被鏈接在該文章底部的 2nd article 被討論。
這最後一個示例與前一個是相反的,一旦一個 channel 被關閉,它的全部的值都會從 buffer 中流失,channel 將當即返回0值。
package main import "fmt" func main() { c := make(chan int, 3) c <- 1 c <- 2 c <- 3 close(c) for i := 0; i < 4; i++ { fmt.Printf("%d ", <-c) // prints 1 2 3 0 } }
點擊這裏運行
針對這個問題的正確的解決辦法是使用 range
循環處理:
for v := range c { // do something with v } for v, ok := <- c; ok ; v, ok = <- c { // do something with v }
這兩個語句在函數中是相等的,展現 range
是作什麼。