感謝參考原文-http://bjbsair.com/2020-03-27/tech-info/7058.html
引言
Goroutine 和 Channel 是 Go 語言并發(fā)編程的兩大基石器罐。Goroutine 用于執(zhí)行并發(fā)任務(wù)檀训,Channel 用于 goroutine 之間的同步、通信踩晶。
在Golang的并發(fā)哲學(xué)里,有一句非常著名的話:
Do not communicate by sharing memory; instead, share memory by communicating.
意思是:不要通過共享內(nèi)存來通信攒磨,而要通過通信來實(shí)現(xiàn)內(nèi)存共享锋玲,它依賴CSP(Communication Sequence Process) 模型,簡稱通信順序進(jìn)程盗迟。
Go提倡使用通信的方法代替共享內(nèi)存坤邪,當(dāng)一個(gè)Goroutine需要和其他Goroutine資源共享時(shí),Channel就會(huì)在他們之間架起一座橋梁罚缕,并提供確保安全同步的機(jī)制艇纺。
Channel本質(zhì)上還是一個(gè)隊(duì)列,遵循FIFO(First In-First Out)原則邮弹,
創(chuàng)建通道
創(chuàng)建通道需要用到關(guān)鍵字 make 黔衡,格式如下:
通道實(shí)例 := make(chan 數(shù)據(jù)類型)
- 數(shù)據(jù)類型:通道內(nèi)傳輸?shù)脑仡愋汀?/li>
- 通道實(shí)例:通過make創(chuàng)建的通道句柄。
使用通道
通道創(chuàng)建后腌乡,就可以使用通道進(jìn)行發(fā)送和接收操作盟劫。
寫入
通道的寫入使用特殊的操作符<-,將數(shù)據(jù)通過通道發(fā)送的格式為:
通道變量 <- 值
(可以簡單理解為箭頭方向?yàn)閭鬟f的值最終去向)
// 創(chuàng)建一個(gè)空接口通道
ch := make(chan interface{})
// 將0放入通道中
ch <- 0
// 將hello字符串放入通道中
ch <- "hello"
讀取
通道的讀取同樣使用<-操作符导饲,通道接收有如下特性:
- 通道的收發(fā)操作在不同的兩個(gè) goroutine 間進(jìn)行捞高。
- 由于通道的數(shù)據(jù)在沒有接收方處理時(shí),數(shù)據(jù)發(fā)送方會(huì)持續(xù)阻塞渣锦,因此通道的接收必定在另外一個(gè) goroutine 中進(jìn)行硝岗。
- 接收將持續(xù)阻塞直到發(fā)送方發(fā)送數(shù)據(jù)。
通道的數(shù)據(jù)接收一共有以下 4 種寫法:
- 阻塞式接收
阻塞模式接收數(shù)據(jù)時(shí)袋毙,接收值只有一個(gè)型檀,格式如下:
data := <-ch
執(zhí)行該語句時(shí)程序?qū)?huì)阻塞,直到接收到數(shù)據(jù)并賦值給 data 變量听盖。
- 非阻塞接收數(shù)據(jù)
使用非阻塞方式從通道接收數(shù)據(jù)時(shí)胀溺,語句不會(huì)發(fā)生阻塞裂七,格式如下:
data, ok := <-ch
data:表示接收到的數(shù)據(jù)。未接收到數(shù)據(jù)時(shí)仓坞,data 為通道類型的零值背零。
ok:表示是否接收到數(shù)據(jù)。
特點(diǎn):非阻塞的通道接收方法可能造成高的 CPU 占用无埃,不建議這么使用徙瓶。
- 忽略接收的數(shù)據(jù)
忽略從通道返回的任何數(shù)據(jù),格式如下:
<-ch
特點(diǎn):該方法也是阻塞的嫉称,必須等到通道返回了程序才會(huì)繼續(xù)往下走侦镇。
- 循環(huán)接收
通道的數(shù)據(jù)接收可以借用 for range 語句進(jìn)行多個(gè)元素的接收操作,格式如下:
for data := range ch {
// do sth.
}
通道 ch 是可以進(jìn)行遍歷的织阅,遍歷的結(jié)果就是接收到的數(shù)據(jù)壳繁。數(shù)據(jù)類型就是通道的數(shù)據(jù)類型。通過 for 遍歷獲得的變量只有一個(gè)荔棉,即上面例子中的 data闹炉。
只讀/只寫通道
一般來說,通道都是雙向的江耀,即數(shù)據(jù)可以進(jìn)入和輸出剩胁。但是,為了符合某些特殊業(yè)務(wù)場景祥国,官方還提供了只支持讀(Read Only)或只支持寫(Write Only)的通道昵观,格式如下:
//定義只讀通道
ch_r := <-chan interface{}
//定義只寫通道
ch_w := <-chan interface{}
有緩沖通道
Go語言中有緩沖的通道(buffered channel)是一種在被接收前能存儲(chǔ)一個(gè)或者多個(gè)值的通道。這種類型的通道并不強(qiáng)制要求 goroutine 之間必須同時(shí)完成發(fā)送和接收舌稀。通道會(huì)阻塞發(fā)送和接收動(dòng)作的條件也會(huì)不同啊犬。只有在通道中沒有要接收的值時(shí),接收動(dòng)作才會(huì)阻塞壁查。只有在通道沒有可用緩沖區(qū)容納被發(fā)送的值時(shí)觉至,發(fā)送動(dòng)作才會(huì)阻塞。
有緩沖通道的定義方式如下:
通道實(shí)例 := make(chan 通道類型, 緩沖大小)
- 通道類型:和無緩沖通道用法一致睡腿,影響通道發(fā)送和接收的數(shù)據(jù)類型语御。
- 緩沖大小:決定通道最多可以保存的元素?cái)?shù)量应闯。
- 通道實(shí)例:被創(chuàng)建出的通道實(shí)例。
下面我借用以下的圖片來說明下這個(gè)通道原理
- 左邊的goroutine不斷的往通道中塞數(shù)據(jù)
- 右邊的goroutine不斷的從通道中拿數(shù)據(jù)
- 一個(gè)讀/一個(gè)寫挂捻,同步作業(yè)
- 左邊的goroutine全部數(shù)據(jù)已經(jīng)放完了碉纺,但此時(shí)通道中還剩余數(shù)據(jù),所有右邊的goroutine還在工作
無緩沖通道
Go語言中無緩沖的通道(unbuffered channel)是指在接收前沒有能力保存任何值的通道。這種類型的通道要求發(fā)送 goroutine 和接收 goroutine 同時(shí)準(zhǔn)備好骨田,才能完成發(fā)送和接收操作耿导。
無緩沖通道的定義方式如下:
通道實(shí)例 := make(chan 通道類型)
- 通道類型:和無緩沖通道用法一致,影響通道發(fā)送和接收的數(shù)據(jù)類型态贤。
- 緩沖大胁丈搿:0
- 通道實(shí)例:被創(chuàng)建出的通道實(shí)例。
為了講得更清楚一些抵卫,我也找了一張額外的圖來說明:
在第 1 步狮荔,兩個(gè) goroutine 都到達(dá)通道,但哪個(gè)都沒有開始執(zhí)行發(fā)送或者接收介粘。在第 2 步,左側(cè)的 goroutine 將它的手伸進(jìn)了通道晚树,這模擬了向通道發(fā)送數(shù)據(jù)的行為姻采。這時(shí),這個(gè) goroutine 會(huì)在通道中被鎖住爵憎,直到交換完成慨亲。在第 3 步,右側(cè)的 goroutine 將它的手放入通道宝鼓,這模擬了從通道里接收數(shù)據(jù)刑棵。這個(gè) goroutine 一樣也會(huì)在通道中被鎖住,直到交換完成愚铡。在第 4 步和第 5 步蛉签,進(jìn)行交換,并最終在第 6 步沥寥,兩個(gè) goroutine 都將它們的手從通道里拿出來碍舍,這模擬了被鎖住的 goroutine 得到釋放。兩個(gè) goroutine 現(xiàn)在都可以去做別的事情了邑雅。
總結(jié)
GoLang的通道是支撐并發(fā)系統(tǒng)穩(wěn)定高效運(yùn)行的重要工具片橡,只有充分了解了它,才能在業(yè)務(wù)開發(fā)和問題排查中找到最關(guān)鍵的方案淮野。知己知彼捧书,百戰(zhàn)不殆。感謝參考原文-http://bjbsair.com/2020-03-27/tech-info/7058/
引言
Goroutine 和 Channel 是 Go 語言并發(fā)編程的兩大基石骤星。Goroutine 用于執(zhí)行并發(fā)任務(wù)经瓷,Channel 用于 goroutine 之間的同步、通信妈踊。
在Golang的并發(fā)哲學(xué)里了嚎,有一句非常著名的話:
Do not communicate by sharing memory; instead, share memory by communicating.
意思是:不要通過共享內(nèi)存來通信,而要通過通信來實(shí)現(xiàn)內(nèi)存共享,它依賴CSP(Communication Sequence Process) 模型歪泳,簡稱通信順序進(jìn)程萝勤。
Go提倡使用通信的方法代替共享內(nèi)存,當(dāng)一個(gè)Goroutine需要和其他Goroutine資源共享時(shí)呐伞,Channel就會(huì)在他們之間架起一座橋梁敌卓,并提供確保安全同步的機(jī)制。
Channel本質(zhì)上還是一個(gè)隊(duì)列伶氢,遵循FIFO(First In-First Out)原則趟径,
創(chuàng)建通道
創(chuàng)建通道需要用到關(guān)鍵字 make ,格式如下:
通道實(shí)例 := make(chan 數(shù)據(jù)類型)
- 數(shù)據(jù)類型:通道內(nèi)傳輸?shù)脑仡愋汀?/li>
- 通道實(shí)例:通過make創(chuàng)建的通道句柄癣防。
使用通道
通道創(chuàng)建后蜗巧,就可以使用通道進(jìn)行發(fā)送和接收操作。
寫入
通道的寫入使用特殊的操作符<-蕾盯,將數(shù)據(jù)通過通道發(fā)送的格式為:
通道變量 <- 值
(可以簡單理解為箭頭方向?yàn)閭鬟f的值最終去向)
// 創(chuàng)建一個(gè)空接口通道
ch := make(chan interface{})
// 將0放入通道中
ch <- 0
// 將hello字符串放入通道中
ch <- "hello"
讀取
通道的讀取同樣使用<-操作符幕屹,通道接收有如下特性:
- 通道的收發(fā)操作在不同的兩個(gè) goroutine 間進(jìn)行。
- 由于通道的數(shù)據(jù)在沒有接收方處理時(shí)级遭,數(shù)據(jù)發(fā)送方會(huì)持續(xù)阻塞望拖,因此通道的接收必定在另外一個(gè) goroutine 中進(jìn)行。
- 接收將持續(xù)阻塞直到發(fā)送方發(fā)送數(shù)據(jù)挫鸽。
通道的數(shù)據(jù)接收一共有以下 4 種寫法:
- 阻塞式接收
阻塞模式接收數(shù)據(jù)時(shí)说敏,接收值只有一個(gè),格式如下:
data := <-ch
執(zhí)行該語句時(shí)程序?qū)?huì)阻塞丢郊,直到接收到數(shù)據(jù)并賦值給 data 變量盔沫。
- 非阻塞接收數(shù)據(jù)
使用非阻塞方式從通道接收數(shù)據(jù)時(shí),語句不會(huì)發(fā)生阻塞蚂夕,格式如下:
data, ok := <-ch
data:表示接收到的數(shù)據(jù)迅诬。未接收到數(shù)據(jù)時(shí),data 為通道類型的零值婿牍。
ok:表示是否接收到數(shù)據(jù)侈贷。
特點(diǎn):非阻塞的通道接收方法可能造成高的 CPU 占用,不建議這么使用等脂。
- 忽略接收的數(shù)據(jù)
忽略從通道返回的任何數(shù)據(jù)俏蛮,格式如下:
<-ch
特點(diǎn):該方法也是阻塞的,必須等到通道返回了程序才會(huì)繼續(xù)往下走上遥。
- 循環(huán)接收
通道的數(shù)據(jù)接收可以借用 for range 語句進(jìn)行多個(gè)元素的接收操作搏屑,格式如下:
for data := range ch {
// do sth.
}
通道 ch 是可以進(jìn)行遍歷的,遍歷的結(jié)果就是接收到的數(shù)據(jù)粉楚。數(shù)據(jù)類型就是通道的數(shù)據(jù)類型辣恋。通過 for 遍歷獲得的變量只有一個(gè)亮垫,即上面例子中的 data。
只讀/只寫通道
一般來說伟骨,通道都是雙向的饮潦,即數(shù)據(jù)可以進(jìn)入和輸出。但是携狭,為了符合某些特殊業(yè)務(wù)場景继蜡,官方還提供了只支持讀(Read Only)或只支持寫(Write Only)的通道,格式如下:
//定義只讀通道
ch_r := <-chan interface{}
//定義只寫通道
ch_w := <-chan interface{}
有緩沖通道
Go語言中有緩沖的通道(buffered channel)是一種在被接收前能存儲(chǔ)一個(gè)或者多個(gè)值的通道逛腿。這種類型的通道并不強(qiáng)制要求 goroutine 之間必須同時(shí)完成發(fā)送和接收稀并。通道會(huì)阻塞發(fā)送和接收動(dòng)作的條件也會(huì)不同。只有在通道中沒有要接收的值時(shí)单默,接收動(dòng)作才會(huì)阻塞碘举。只有在通道沒有可用緩沖區(qū)容納被發(fā)送的值時(shí),發(fā)送動(dòng)作才會(huì)阻塞雕凹。
有緩沖通道的定義方式如下:
通道實(shí)例 := make(chan 通道類型, 緩沖大小)
- 通道類型:和無緩沖通道用法一致殴俱,影響通道發(fā)送和接收的數(shù)據(jù)類型。
- 緩沖大忻兜帧:決定通道最多可以保存的元素?cái)?shù)量。
- 通道實(shí)例:被創(chuàng)建出的通道實(shí)例明场。
下面我借用以下的圖片來說明下這個(gè)通道原理
- 左邊的goroutine不斷的往通道中塞數(shù)據(jù)
- 右邊的goroutine不斷的從通道中拿數(shù)據(jù)
- 一個(gè)讀/一個(gè)寫汽摹,同步作業(yè)
- 左邊的goroutine全部數(shù)據(jù)已經(jīng)放完了,但此時(shí)通道中還剩余數(shù)據(jù)苦锨,所有右邊的goroutine還在工作
無緩沖通道
Go語言中無緩沖的通道(unbuffered channel)是指在接收前沒有能力保存任何值的通道逼泣。這種類型的通道要求發(fā)送 goroutine 和接收 goroutine 同時(shí)準(zhǔn)備好,才能完成發(fā)送和接收操作舟舒。
無緩沖通道的定義方式如下:
通道實(shí)例 := make(chan 通道類型)
- 通道類型:和無緩沖通道用法一致拉庶,影響通道發(fā)送和接收的數(shù)據(jù)類型。
- 緩沖大型豪:0
- 通道實(shí)例:被創(chuàng)建出的通道實(shí)例氏仗。
為了講得更清楚一些,我也找了一張額外的圖來說明:
在第 1 步夺鲜,兩個(gè) goroutine 都到達(dá)通道皆尔,但哪個(gè)都沒有開始執(zhí)行發(fā)送或者接收。在第 2 步币励,左側(cè)的 goroutine 將它的手伸進(jìn)了通道慷蠕,這模擬了向通道發(fā)送數(shù)據(jù)的行為。這時(shí)食呻,這個(gè) goroutine 會(huì)在通道中被鎖住流炕,直到交換完成澎现。在第 3 步,右側(cè)的 goroutine 將它的手放入通道每辟,這模擬了從通道里接收數(shù)據(jù)剑辫。這個(gè) goroutine 一樣也會(huì)在通道中被鎖住,直到交換完成影兽。在第 4 步和第 5 步揭斧,進(jìn)行交換,并最終在第 6 步峻堰,兩個(gè) goroutine 都將它們的手從通道里拿出來讹开,這模擬了被鎖住的 goroutine 得到釋放。兩個(gè) goroutine 現(xiàn)在都可以去做別的事情了捐名。
總結(jié)
GoLang的通道是支撐并發(fā)系統(tǒng)穩(wěn)定高效運(yùn)行的重要工具旦万,只有充分了解了它,才能在業(yè)務(wù)開發(fā)和問題排查中找到最關(guān)鍵的方案镶蹋。知己知彼成艘,百戰(zhàn)不殆。