Golang Channel詳解

感謝參考原文-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ī)制艇纺。

Golang Channel詳細(xì)解析

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"

讀取

通道的讀取同樣使用<-操作符导饲,通道接收有如下特性:

  1. 通道的收發(fā)操作在不同的兩個(gè) goroutine 間進(jìn)行捞高。
  2. 由于通道的數(shù)據(jù)在沒有接收方處理時(shí),數(shù)據(jù)發(fā)送方會(huì)持續(xù)阻塞渣锦,因此通道的接收必定在另外一個(gè) goroutine 中進(jìn)行硝岗。
  3. 接收將持續(xù)阻塞直到發(fā)送方發(fā)送數(shù)據(jù)。

通道的數(shù)據(jù)接收一共有以下 4 種寫法:

  1. 阻塞式接收

阻塞模式接收數(shù)據(jù)時(shí)袋毙,接收值只有一個(gè)型檀,格式如下:

data := <-ch

執(zhí)行該語句時(shí)程序?qū)?huì)阻塞,直到接收到數(shù)據(jù)并賦值給 data 變量听盖。

  1. 非阻塞接收數(shù)據(jù)

使用非阻塞方式從通道接收數(shù)據(jù)時(shí)胀溺,語句不會(huì)發(fā)生阻塞裂七,格式如下:

data, ok := <-ch

data:表示接收到的數(shù)據(jù)。未接收到數(shù)據(jù)時(shí)仓坞,data 為通道類型的零值背零。

ok:表示是否接收到數(shù)據(jù)。

特點(diǎn):非阻塞的通道接收方法可能造成高的 CPU 占用无埃,不建議這么使用徙瓶。

  1. 忽略接收的數(shù)據(jù)

忽略從通道返回的任何數(shù)據(jù),格式如下:

<-ch

特點(diǎn):該方法也是阻塞的嫉称,必須等到通道返回了程序才會(huì)繼續(xù)往下走侦镇。

  1. 循環(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è)通道原理

Golang Channel詳細(xì)解析
  1. 左邊的goroutine不斷的往通道中塞數(shù)據(jù)
  2. 右邊的goroutine不斷的從通道中拿數(shù)據(jù)
  3. 一個(gè)讀/一個(gè)寫挂捻,同步作業(yè)
  4. 左邊的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í)例。

為了講得更清楚一些抵卫,我也找了一張額外的圖來說明:

Golang Channel詳細(xì)解析

在第 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ī)制。

Golang Channel詳細(xì)解析

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"

讀取

通道的讀取同樣使用<-操作符幕屹,通道接收有如下特性:

  1. 通道的收發(fā)操作在不同的兩個(gè) goroutine 間進(jìn)行。
  2. 由于通道的數(shù)據(jù)在沒有接收方處理時(shí)级遭,數(shù)據(jù)發(fā)送方會(huì)持續(xù)阻塞望拖,因此通道的接收必定在另外一個(gè) goroutine 中進(jìn)行。
  3. 接收將持續(xù)阻塞直到發(fā)送方發(fā)送數(shù)據(jù)挫鸽。

通道的數(shù)據(jù)接收一共有以下 4 種寫法:

  1. 阻塞式接收

阻塞模式接收數(shù)據(jù)時(shí)说敏,接收值只有一個(gè),格式如下:

data := <-ch

執(zhí)行該語句時(shí)程序?qū)?huì)阻塞丢郊,直到接收到數(shù)據(jù)并賦值給 data 變量盔沫。

  1. 非阻塞接收數(shù)據(jù)

使用非阻塞方式從通道接收數(shù)據(jù)時(shí),語句不會(huì)發(fā)生阻塞蚂夕,格式如下:

data, ok := <-ch

data:表示接收到的數(shù)據(jù)迅诬。未接收到數(shù)據(jù)時(shí),data 為通道類型的零值婿牍。

ok:表示是否接收到數(shù)據(jù)侈贷。

特點(diǎn):非阻塞的通道接收方法可能造成高的 CPU 占用,不建議這么使用等脂。

  1. 忽略接收的數(shù)據(jù)

忽略從通道返回的任何數(shù)據(jù)俏蛮,格式如下:

<-ch

特點(diǎn):該方法也是阻塞的,必須等到通道返回了程序才會(huì)繼續(xù)往下走上遥。

  1. 循環(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è)通道原理

Golang Channel詳細(xì)解析
  1. 左邊的goroutine不斷的往通道中塞數(shù)據(jù)
  2. 右邊的goroutine不斷的從通道中拿數(shù)據(jù)
  3. 一個(gè)讀/一個(gè)寫汽摹,同步作業(yè)
  4. 左邊的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í)例氏仗。

為了講得更清楚一些,我也找了一張額外的圖來說明:

Golang Channel詳細(xì)解析

在第 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)不殆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末贺归,一起剝皮案震驚了整個(gè)濱河市淆两,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拂酣,老刑警劉巖秋冰,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異婶熬,居然都是意外死亡剑勾,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進(jìn)店門赵颅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來虽另,“玉大人,你說我怎么就攤上這事饺谬∥娲蹋” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵商蕴,是天一觀的道長叠萍。 經(jīng)常有香客問我,道長绪商,這世上最難降的妖魔是什么苛谷? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮格郁,結(jié)果婚禮上腹殿,老公的妹妹穿的比我還像新娘独悴。我一直安慰自己,他們只是感情好锣尉,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布刻炒。 她就那樣靜靜地躺著,像睡著了一般自沧。 火紅的嫁衣襯著肌膚如雪坟奥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天拇厢,我揣著相機(jī)與錄音爱谁,去河邊找鬼。 笑死孝偎,一個(gè)胖子當(dāng)著我的面吹牛访敌,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播衣盾,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼寺旺,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了势决?” 一聲冷哼從身側(cè)響起阻塑,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎果复,沒想到半個(gè)月后叮姑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡据悔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了耘沼。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片极颓。...
    茶點(diǎn)故事閱讀 40,001評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖群嗤,靈堂內(nèi)的尸體忽然破棺而出菠隆,到底是詐尸還是另有隱情,我是刑警寧澤狂秘,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布骇径,位于F島的核電站,受9級(jí)特大地震影響者春,放射性物質(zhì)發(fā)生泄漏破衔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一钱烟、第九天 我趴在偏房一處隱蔽的房頂上張望晰筛。 院中可真熱鬧嫡丙,春花似錦、人聲如沸读第。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽怜瞒。三九已至父泳,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間吴汪,已是汗流浹背惠窄。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留浇坐,地道東北人睬捶。 一個(gè)月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像近刘,于是被迫代替她去往敵國和親擒贸。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,955評論 2 355

推薦閱讀更多精彩內(nèi)容