這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
轉自:http://studygolang.com/articles/2410
channel預設上是阻塞的,也就是說,如果Channel滿了,就阻塞寫,如果Channel空了,就阻塞讀。阻塞的含義就是一直等到輪到它為止。單有時候我們會收到 fatal error: all goroutines are asleep - deadlock! 異常,這是如何呢?
代碼例子:
package main
import "fmt"
func main() {
channel := make(chan string, 2)
fmt.Println("1")
channel <- "h1"
fmt.Println("2")
channel <- "w2"
fmt.Println("3")
channel <- "c3" // 執行到這一步,直接報 error
fmt.Println("...")
msg1 := <-channel
fmt.Println(msg1)
}
執行效果:
參考:
http://stackoverflow.com/questions/26927479/go-language-fatal-error-all-goroutines-are-asleep-deadlock
fatal error: all goroutines are asleep - deadlock!
出錯資訊的意思是:
在main goroutine線,期望從管道中獲得一個資料,而這個資料必須是其他goroutine線放入管道的
但是其他goroutine線都已經執行完了(all goroutines are asleep),那麼就永遠不會有資料放入管道。
所以,main goroutine線在等一個永遠不會來的資料,那整個程式就永遠等下去了。
這顯然是沒有結果的,所以這個程式就說“算了吧,不堅持了,我自己自殺掉,報一個錯給代碼作者,我被deadlock了”
這裡是系統自動在除了主協程之外的協程都關閉後,做的檢查,繼而報出的錯誤, 證明思路如下, 在100秒內, 我們看不到異常, 100秒後,系統報錯。
package main
import (
"fmt"
"time"
)
func main() {
channel := make(chan string, 2)
go func() {
fmt.Println("sleep 1")
time.Sleep(100 * time.Second)
fmt.Println("sleep 2")
}()
fmt.Println("1")
channel <- "h1"
fmt.Println("2")
channel <- "w2"
fmt.Println("3")
channel <- "c3"
fmt.Println("...")
msg1 := <-channel
fmt.Println(msg1)
}
100秒內執行效果:
100秒後執行效果:
如果避免上面異常拋出呢?這時候我們可以用 select來幫我們處理。
package main
import "fmt"
func main() {
channel := make(chan string, 2)
fmt.Println("1")
channel <- "h1"
fmt.Println("2")
channel <- "w2"
fmt.Println("3")
select {
case channel <- "c3":
fmt.Println("ok")
default:
fmt.Println("channel is full !")
}
fmt.Println("...")
msg1 := <-channel
fmt.Println(msg1)
}
執行效果:
這時候,我們把第三個要寫入的 chan 拋棄了。
上面的例子中是寫的例子, 讀的例子也一樣,下面的異常是 ws := <-channel 這一行拋出的。
channel := make(chan string, 2)
fmt.Println("begin")
ws := <-channel
fmt.Println(ws)