Goroutine 和 Channel 是 Go 語言併發編程的兩大基石。Goroutine 用於執行併發任務,Channel 用於 goroutine 之間的同步、通訊。編程
在Golang的併發哲學裏,有一句很是著名的話:安全
Do not communicate by sharing memory; instead, share memory by communicating.
意思是:不要經過共享內存來通訊,而要經過通訊來實現內存共享,它依賴CSP(Communication Sequence Process) 模型,簡稱通訊順序進程。併發
Go提倡使用通訊的方法代替共享內存,當一個Goroutine須要和其餘Goroutine資源共享時,Channel就會在他們之間架起一座橋樑,並提供確保安全同步的機制。工具
Channel本質上仍是一個隊列,遵循FIFO(First In-First Out)原則,spa
建立通道須要用到關鍵字make,格式以下:3d
通道實例 := make(chan 數據類型)
通道建立後,就可使用通道進行發送和接收操做。code
通道的寫入使用特殊的操做符<-,將數據經過通道發送的格式爲:blog
通道變量 <- 值
(能夠簡單理解爲箭頭方向爲傳遞的值最終去向)接口
// 建立一個空接口通道 ch := make(chan interface{}) // 將0放入通道中 ch <- 0 // 將hello字符串放入通道中 ch <- "hello"
通道的讀取一樣使用<-操做符,通道接收有以下特性:隊列
通道的數據接收一共有如下 4 種寫法:
1) 阻塞式接收
阻塞模式接收數據時,接收值只有一個,格式以下:
data := <-ch
執行該語句時程序將會阻塞,直到接收到數據並賦值給 data 變量。
2) 非阻塞接收數據
使用非阻塞方式從通道接收數據時,語句不會發生阻塞,格式以下:
data, ok := <-ch
data:表示接收到的數據。未接收到數據時,data 爲通道類型的零值。
ok:表示是否接收到數據。
特色:非阻塞的通道接收方法可能形成高的 CPU 佔用,不建議這麼使用。
3) 忽略接收的數據
忽略從通道返回的任何數據,格式以下:
<-ch
特色:該方法也是阻塞的,必須等到通道返回了程序纔會繼續往下走。
4) 循環接收
通道的數據接收能夠借用 for range 語句進行多個元素的接收操做,格式以下:
for data := range ch { // do sth. }
通道 ch 是能夠進行遍歷的,遍歷的結果就是接收到的數據。數據類型就是通道的數據類型。經過 for 遍歷得到的變量只有一個,即上面例子中的 data。
通常來講,通道都是雙向的,即數據能夠進入和輸出。可是,爲了符合某些特殊業務場景,官方還提供了只支持讀(Read Only)或只支持寫(Write Only)的通道,格式以下:
//定義只讀通道 ch_r := <-chan interface{} //定義只寫通道 ch_w := <-chan interface{}
Go語言中有緩衝的通道(buffered channel)是一種在被接收前能存儲一個或者多個值的通道。這種類型的通道並不強制要求 goroutine 之間必須同時完成發送和接收。通道會阻塞發送和接收動做的條件也會不一樣。只有在通道中沒有要接收的值時,接收動做纔會阻塞。只有在通道沒有可用緩衝區容納被髮送的值時,發送動做纔會阻塞。
有緩衝通道的定義方式以下:
通道實例 := make(chan 通道類型, 緩衝大小)
下面我借用如下的圖片來講明下這個通道原理
Go語言中無緩衝的通道(unbuffered channel)是指在接收前沒有能力保存任何值的通道。這種類型的通道要求發送 goroutine 和接收 goroutine 同時準備好,才能完成發送和接收操做。
無緩衝通道的定義方式以下:
通道實例 := make(chan 通道類型)
爲了講得更清楚一些,我也找了一張額外的圖來講明:
在第 1 步,兩個 goroutine 都到達通道,但哪一個都沒有開始執行發送或者接收。在第 2 步,左側的 goroutine 將它的手伸進了通道,這模擬了向通道發送數據的行爲。這時,這個 goroutine 會在通道中被鎖住,直到交換完成。在第 3 步,右側的 goroutine 將它的手放入通道,這模擬了從通道里接收數據。這個 goroutine 同樣也會在通道中被鎖住,直到交換完成。在第 4 步和第 5 步,進行交換,並最終在第 6 步,兩個 goroutine 都將它們的手從通道里拿出來,這模擬了被鎖住的 goroutine 獲得釋放。兩個 goroutine 如今均可以去作別的事情了。
GoLang的通道是支撐併發系統穩定高效運行的重要工具,只有充分了解了它,才能在業務開發和問題排查中找到最關鍵的方案。知己知彼,百戰不殆。