管道(Channel)是Go語言中比較重要的部分,常常在Go中的併發中使用。今天嘗試對Go語言的管道來作如下總結。總結的形式採用問答式的方法,讓答案更有目的性。
Q1.管道是什麼?
管道是Go語言在語言級別上提供的goroutine間的**通信方式**,咱們能夠使用channel在多個goroutine之間傳遞消息。channel是**進程內**的通信方式,是不支持跨進程通訊的,若是須要進程間通信的話,能夠使用Socket等網絡方式。
以上是管道的概念,下面咱們就看下管道的語法。
Q2.管道的語法?
整個Go語言的語法都比較簡潔,管道也不例外,其語法以下所示:
在此應當注意,管道是類型相關的,即一個管道只能傳遞一種類型的值。管道中的數據是先進先出的。網絡
1 // 聲明方式,在此ElemType是指此管道所傳遞的類型 2 var chanName chan ElemType 3 // 聲明一個傳遞類型爲int的管道 4 var ch chan int 5 // 聲明一個map,元素是bool型的channel 6 var m map[string] chan bool 7 8 // 定義語法,定義須要使用內置函數make()便可,下面這行代碼是聲明+定義一個整型管道 9 ch := make(chan int) 10 // 事先定義好管道的size,下面這行代碼定義管道的size爲100 11 ch := make(chan int, 100) 12 13 // 由管道中讀寫數據,<-操做符是與最左邊的chan優先結合的 14 // 向管道中寫入一個數據,在此須要注意:向管道中寫入數據一般會致使程序阻塞,直到有 15 // 其餘goroutine從這個管道中讀取數據 16 ch<- value 17 // 讀取數據,注意:若是管道中沒有數據,那麼從管道中讀取數據會致使程序阻塞,直到有數據 18 value := <-ch 19 20 // 單向管道 21 var ch1 chan<- float64 // 只能向裏面寫入float64的數據,不能讀取 22 var ch2 <-chan int // 只能讀取int型數據 23 24 // 關閉channel,直接調用close()便可 25 close(ch) 26 // 判斷ch是否關閉,判斷ok的值,若是是false,則說明已經關閉(關閉的話讀取是不會阻塞的) 27 x, ok := <-ch
Q3.管道的使用場景?
在第一個問題中,咱們已經知道管道能夠作進程間通信,Go中自帶了對協程的支持(關鍵字go),而管道就是各個協程間通信的一個方法。這裏咱們舉些簡單的小例子來講明一下管道如何在協程中使用。多線程
1 package main 2 import "fmt" 3 4 func print() { 5 fmt.Println("Hello world") 6 } 7 8 func main() { 9 for i := 0; i < 10; i++ { 10 go print() 11 } 12 }
上面的代碼意思大體是:使用協程來並行輸出10次 "Hello world", 可是你們運行上面代碼的時候,會發現不會有輸出。這是由於雖然使用go關鍵字進行了協程的建立,可是尚未等到執行的時候,main函數已經退出來了,進程已經關閉,因此起來的協程也不會被執行。
若是你有C相關的多線程經驗時,可已經將協程改成線程,以後調用線程的join方法,讓主線程等待子線程執行完畢後再退出。而在Go語言中,咱們能夠利用管道的寫入阻塞和讀取阻塞來完成相似線程join的行爲。代碼以下所示:
併發
1 package main 2 import "fmt" 3 4 func print(ch chan int) { 5 fmt.Println("Hello world") 6 ch<- 1 7 } 8 9 func main() { 10 chs := make([]chan int) 11 for i := 0; i < 10; i++ { 12 chs[i] = make(chan int) 13 go print(chs[i]) 14 } 15 16 for _, ch := range(chs){ 17 <-ch 18 } 19 }
經過以上代碼,咱們就能夠完成了並行輸出10此Hello world 的效果。
有一個問題留給你們,若是將 print改成函數
1 func print(ch chan int){ 2 ch<- 1 3 fmt.Println("Hello world") 4 }
會打印出什麼呢?
因爲水平有限,不免會有錯誤,請你們指正。
謝謝。
[3/30]
spa