【Go 語言社群】golang協程——通道channel阻塞
說到channel,就一定要說一說執行緒了。任何實際專案,無論大小,併發是必然存在的。併發的存在,就涉及到執行緒通訊。在當下的開發語言中,執行緒通訊主要有兩種,共享記憶體與訊息傳遞。共享記憶體一定都很熟悉,通過共同操作同一物件,實現執行緒間通訊。訊息傳遞即通過類似聊天的方式。golang對併發的處理採用了協程的技術。golang的goroutine就是協程的實現。協程的概念很早就有,簡單的理解為輕量級執行緒,goroutine就是為了解決併發任務間的通訊而設計的。golang解決通訊的理念是:不要通過共享記憶體來通訊,而應該通過通訊來共享記憶體。golang解決方案是訊息傳遞機制,訊息的傳遞就是通過channel來實現的。
channel的使用很簡單,這裡就不在粘別人的東西了。現在談一談對channe阻塞l的理解。
傳送者角度:對於同一個通道,傳送操作(協程或者函式中的),在接收者準備好之前是阻塞的。如果chan中的資料無人接收,就無法再給通道傳入其他資料。因為新的輸入無法在通道非空的情況下傳入。所以傳送操作會等待 chan 再次變為可用狀態:就是通道值被接收時(可以傳入變數)。
接收者角度:對於同一個通道,接收操作是阻塞的(協程或函式中的),直到傳送者可用:如果通道中沒有資料,接收者就阻塞了。
通過一個簡單的例子來說明:
package main import ( "fmt" ) func f1(in chan int) { fmt.Println(<-in) } func main() { out := make(chan int) out <- 2 go f1(out) }
執行結果:fatal error: all goroutines are asleep - deadlock!
這是由於第13行之前不存在對out的接收,所以,對於out <- 2來說,永遠是阻塞的,即一直會等下去。
將13,14行互換
1 package main 2 3 import ( 4 "fmt" 5 ) 6 7 func f1(in chan int) { 8 fmt.Println(<-in) 9 } 10 11 func main() { 12 out := make(chan int) 13 go f1(out) 14 out <- 2 15 }
執行結果:2
14行前存在對管道的讀操作,所以out <- 2 是合法的。就像前文說的,傳送操作在接收者準備好之前是阻塞的。