最近學go的channel的時候老是遇到題目中的錯誤:
fatal error: all goroutines are asleep - deadlock!
對問題研究總結後,在此記錄一下
下貼上錯誤代碼:
func testDeadLock(c chan int){
for{
fmt.Println(<-c)
}
}
func main() {
c :=make(chan int)
c<-'A'
go testDeadLock(c)
time.Sleep(time.Millisecond)
}
看上面main函數中,先開了一個通道channel c,然後馬上對這個c內寫入數據。
然後調協程testDeadLock在c中取數據,結果運行時報錯:
fatal error: all goroutines are asleep - deadlock!
這究竟是咋回事呢?
首先我們這裏通過make(chan int),開闢的通道是一種無緩衝通道,所以當對這個緩衝通道寫的時候,會一直阻塞等到某個協程對這個緩衝通道讀(大家發現沒有這個與典型的生產者消費者有點不一樣,當隊列中“內容”已經滿了,生產者再生往裏放東西纔會阻塞,而這裏我講c<-'A’理解爲生產,他卻是需要等到某個協程讀了再能繼續運行)。
main函數的執行在go語言中本身就是一個協程的執行,所以在執行到c<-'A’的時候,執行main函數的協程將被阻塞,換句話說main函數被阻塞了,此時不能在繼續往下執行了,所以go testDeadLock©這個函數無法執行到了,就無法讀到c中的內容了,所以整個程序阻塞,發生了死鎖。
如何解決這個問題呢?大家想一下,我們阻塞的原因是main函數不能繼續向下執行了,所以go testDeadLock©執行不到,對吧,那我們在main函數中另開一個協程,讓他對c進行寫(對c進行寫的過程不在main函數對應的協程中做),修改後的代碼:
func test(c chan int){
c<-'A'
}
func testDeadLock(c chan int){
for{
fmt.Println(<-c)
}
}
func main() {
//chanDemo()
c :=make(chan int)
go test(c)
go testDeadLock(c)
time.Sleep(time.Millisecond)
}
新增了test函數,在main函數中爲test函數開了協程專門執行,讓對c的寫在test中進行,這樣main函數就能繼續往下執行,去開一個協程執行testDeadLock函數了,這樣一來,雖然剛剛開的test函數中會因爲對c的寫入發生阻塞但並不會影響main函數對應協程的繼續執行,所以之後的testDeadLock馬上將從c中讀出test函數剛剛寫入的內容,這樣一來 test中對c寫入的內容就被testDeadLock順利讀出並打印了。