之前的例子創建的都是無緩衝通道。使用無緩衝通道往裏面裝數據時,裝入方將被阻塞,直到另外通道在另一個goroutine中被取出,同時,如果通道中沒有放入任何數據,接收方試圖從通道中獲取數據時,同樣也是阻塞。發送和接收的操作是同步完成的。
下面介紹一個併發打印的例子,將goroutine和channel放在一起展示它們的用法;
package main
import "fmt"
func printer(c chan int) {
//開始無限循環等待數據
for {
//從channel 中獲取一個數據
data := <-c
//將0視爲數據結束
if data == 0 {
break
}
//打印數據
fmt.Println(data)
}
//通知main已經結束循環(我搞定了)
c <- 0
}
func main() {
//創建一個channel
c := make(chan int)
//併發執行printer,傳入channel
go printer(c)
for i := 1; i <= 10; i++ {
//將數據通過channel投送給printer
c <- i
}
//通知併發的printer結束循環(沒有數據啦)
c <- 0
//等待printer結束(搞定喊我)
<-c
}
運行輸出:
1
2
3
4
5
6
7
8
9
10
成功: 進程退出代碼 0.
代碼說明:
- 本例設計模式就是典型的生產者和消費者。生產者是第
- 37 行的循環,而消費者是 printer() 函數。整個例子使用了兩個 goroutine,一個是 main(),一個是通過第 35 行 printer() 函數創建的 goroutine。兩個 goroutine 通過第 32 行創建的通道進行通信。這個通道有下面兩重功能。
- 數據傳送:第 40 行中發送數據和第 13 行接收數據。
- 控制指令:類似於信號量的功能。同步 goroutine 的操作。功能簡單描述爲:
- 第 44 行:“沒數據啦!”
- 第 25 行:“我搞定了!”
- 第 47 行:“搞定喊我!”
- 第 10 行,創建一個無限循環,只有當第 16 行獲取到的數據爲 0 時纔會退出循環。
- 第 13 行,從函數參數傳入的通道中獲取一個整型數值。
- 第 21 行,打印整型數值。
- 第 25 行,在退出循環時,通過通道通知 main() 函數已經完成工作。
- 第 32 行,創建一個整型通道進行跨 goroutine 的通信。
- 第 35 行,創建一個 goroutine,併發執行 printer() 函數。
- 第 37 行,構建一個數值循環,將 1~10 的數通過通道傳送給 printer 構造出的 goroutine。
- 第 44 行,給通道傳入一個 0,表示將前面的數據處理完成後,退出循環。
- 第 47 行,在數據發送過去後,因爲併發和調度的原因,任務會併發執行。這裏需要等待 printer 的第 25 行返回數據後,纔可以退出 main()。