1. 程式人生 > 其它 >【Go 語言社群】golang協程——通道channel阻塞

【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 是合法的。就像前文說的,傳送操作在接收者準備好之前是阻塞的。