深入理解channel:設(shè)計(jì)+源碼

channel是大家在Go中用的最頻繁的特性,也是Go最自豪的特性之一蛉加,你有沒(méi)有思考過(guò):

  • Why:為什么要設(shè)計(jì)channel曹步?
  • What:channel是什么樣的径荔?
  • How:channel是如何實(shí)現(xiàn)的?

這篇文章颠黎,就來(lái)回答這3個(gè)問(wèn)題另锋。

channel解決什么問(wèn)題?

在Golang誕生之前狭归,各編程語(yǔ)言都使用多線程進(jìn)行編程夭坪,但多線程復(fù)雜、混亂过椎、難以管理室梅,對(duì)開(kāi)發(fā)者并不是多么友好。

Golang是Google為了解決高并發(fā)搜索而設(shè)計(jì)的潭流,它們想使用簡(jiǎn)單的方式竞惋,高效解決并發(fā)問(wèn)題,最后做成了灰嫉,然后又把Golang開(kāi)源了出來(lái)拆宛,以及到處推廣,所以Golang自從誕生之初讼撒,就風(fēng)風(fēng)火火浑厚。

從Golang文檔中,我們可以知道根盒,為啥Golang設(shè)計(jì)了channel钳幅,以及channel解決了什么問(wèn)題?

Go Concurrency Patterns:

Concurrency is the key to designing high performance network services. Go's concurrency primitives (goroutines and channels) provide a simple and efficient means of expressing concurrent execution. In this talk we see how tricky concurrency problems can be solved gracefully with simple Go code.

Golang使用goroutinechannel簡(jiǎn)單炎滞、高效的解決并發(fā)問(wèn)題敢艰,channel解決的是goroutine之間的通信

channel是怎么設(shè)計(jì)的册赛?

我們以為channel是一個(gè)通道:

image

實(shí)際上钠导,channel的內(nèi)在是這樣的:

image

channel設(shè)計(jì)涉及的數(shù)據(jù)結(jié)構(gòu)很簡(jiǎn)單:

  • 基于數(shù)組的循環(huán)隊(duì)列,有緩沖的channel用它暫存數(shù)據(jù)
  • 基于鏈表的單向隊(duì)列森瘪,用于保存阻塞在此channel上的goroutine

我本來(lái)想自己碼一篇channel的設(shè)計(jì)文章牡属,但已經(jīng)有大牛:Kavya深入分析了Channel的設(shè)計(jì),我也相信自己寫的肯定不如他好扼睬,所以我把Kavya在Gopher Con上的PPT推薦給你逮栅,如果你希望成為Go大牛,你一定要讀一下,現(xiàn)在請(qǐng)收藏好措伐。

Kavya在Gopher Con上的演講主題是:理解channel特纤,他并不是教你如何使用channel,而是把channel的設(shè)計(jì)和goroutine的調(diào)度結(jié)合起來(lái)废士,從內(nèi)在方式向你介紹叫潦。這份PPT足足有80頁(yè),包含了大量的動(dòng)畫官硝,非常容易理解矗蕊,你會(huì)了解到:

  • channel的創(chuàng)建
  • 各種場(chǎng)景的發(fā)送和接收
  • goroutine的調(diào)度
  • goroutine的阻塞和喚醒
  • channel和goroutine在select操作下

Kavya的PPT應(yīng)該包含了channel的80%的設(shè)計(jì)思想,但也有一些缺失氢架,需要你閱讀源碼:

  • channel關(guān)閉時(shí)傻咖,gorontine的處理
  • 創(chuàng)建channel時(shí),不同的創(chuàng)建方法
  • 讀channel時(shí)的非阻塞操作
  • ...

PPT在此:Understanding Channels岖研,如果你有心卿操,還可以在這個(gè)網(wǎng)站看到Kavya關(guān)于goroutine調(diào)度的PPT,福利哦??孙援。(訪問(wèn)不了請(qǐng)翻墻害淤,或閱讀原文從博客文章最下面看Github備份)

channel是怎么實(shí)現(xiàn)的?

chan.go是channel的主要實(shí)現(xiàn)文件拓售,只有700行窥摄,十分佩服Go團(tuán)隊(duì),實(shí)現(xiàn)的如此精簡(jiǎn)础淤,卻發(fā)揮如此大的作用U阜拧!鸽凶!

看完Kavya的PPT币砂,你已經(jīng)可以直接看channel的源碼了,如果有任何問(wèn)題玻侥,思考一下你也可以想通决摧,如果有任何問(wèn)題可博客文章留言或公眾號(hào)私信進(jìn)行討論。

另外凑兰,推薦一篇在Medium(國(guó)外高質(zhì)量文章社區(qū))上獲得500+贊的源碼分析文章掌桩,非常詳細(xì)。

文章鏈接:Diving deep into the golang channels

我學(xué)到了什么票摇?

閱讀channel源碼我學(xué)到了一些東西拘鞋,分享給大家砚蓬。

channel的4個(gè)特性的實(shí)現(xiàn):

  • channel的goroutine安全矢门,是通過(guò)mutex實(shí)現(xiàn)的。
  • channel的FIFO,是通過(guò)循環(huán)隊(duì)列實(shí)現(xiàn)的祟剔。
  • channel的通信:在goroutine間傳遞數(shù)據(jù)隔躲,是通過(guò)僅共享hchan+數(shù)據(jù)拷貝實(shí)現(xiàn)的。
  • channel的阻塞是通過(guò)goroutine自己掛起物延,喚醒goroutine是通過(guò)對(duì)方goroutine喚醒實(shí)現(xiàn)的宣旱。

channel的其他實(shí)現(xiàn):

  • 發(fā)送goroutine是可以訪問(wèn)接收goroutine的內(nèi)存空間的,接收goroutine也是可以直接訪問(wèn)發(fā)送goroutine的內(nèi)存空間的叛薯,看sendDirect浑吟、recvDirect函數(shù)。
  • 無(wú)緩沖的channel始終都是直接訪問(wèn)對(duì)方goroutine內(nèi)存的方式耗溜,把手伸到別人的內(nèi)存,把數(shù)據(jù)放到接收變量的內(nèi)存,或者從發(fā)送goroutine的內(nèi)存拷貝到自己內(nèi)存术陶。省掉了對(duì)方再加鎖獲取數(shù)據(jù)的過(guò)程缘缚。
  • 接收goroutine讀不到數(shù)據(jù)和發(fā)送goroutine無(wú)法寫入數(shù)據(jù)時(shí),是把自己掛起的阿宅,這就是channel的阻塞操作候衍。阻塞的接收goroutine是由發(fā)送goroutine喚醒的,阻塞的發(fā)送goroutine是由接收goroutine喚醒的洒放,看gopark蛉鹿、goready函數(shù)在chan.go中的調(diào)用。
  • 接收goroutine當(dāng)channel關(guān)閉時(shí)拉馋,讀channel會(huì)得到0值榨为,并不是channel保存了0值,而是它發(fā)現(xiàn)channel關(guān)閉了煌茴,把接收數(shù)據(jù)的變量的值設(shè)置為0值随闺。
  • channel的操作/調(diào)用,是通過(guò)reflect實(shí)現(xiàn)的蔓腐,可以看reflect包的makechan, chansend, chanrecv函數(shù)矩乐。

如果閱讀chan_test.go還會(huì)學(xué)到一些騷操作,比如:

if <-stopCh {
    // do stop
}

而不是寫成:

if stop := <-stopCh; stop {
    // do stop
}

這就是關(guān)于channel的設(shè)計(jì)和實(shí)現(xiàn)的分享回论,希望你通過(guò)Kavya的PPT和代碼閱讀能深入了解channel散罕。

鏈接

  1. 如果這篇文章對(duì)你有幫助,請(qǐng)點(diǎn)個(gè)贊/喜歡傀蓉,感謝欧漱。
  2. 本文作者:大彬
  3. 如果喜歡本文,隨意轉(zhuǎn)載葬燎,但請(qǐng)保留此原文鏈接:http://www.lessisbetter.site/2019/03/03/golang-channel-design-and-source/
image
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末误甚,一起剝皮案震驚了整個(gè)濱河市缚甩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌窑邦,老刑警劉巖擅威,帶你破解...
    沈念sama閱讀 206,482評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異冈钦,居然都是意外死亡郊丛,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門瞧筛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)厉熟,“玉大人,你說(shuō)我怎么就攤上這事较幌∏烀ǎ” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,762評(píng)論 0 342
  • 文/不壞的土叔 我叫張陵绅络,是天一觀的道長(zhǎng)月培。 經(jīng)常有香客問(wèn)我,道長(zhǎng)恩急,這世上最難降的妖魔是什么杉畜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,273評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮衷恭,結(jié)果婚禮上此叠,老公的妹妹穿的比我還像新娘。我一直安慰自己随珠,他們只是感情好灭袁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,289評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著窗看,像睡著了一般茸歧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上显沈,一...
    開(kāi)封第一講書(shū)人閱讀 49,046評(píng)論 1 285
  • 那天软瞎,我揣著相機(jī)與錄音,去河邊找鬼拉讯。 笑死涤浇,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的魔慷。 我是一名探鬼主播只锭,決...
    沈念sama閱讀 38,351評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼院尔!你這毒婦竟也來(lái)了蜻展?” 一聲冷哼從身側(cè)響起页滚,我...
    開(kāi)封第一講書(shū)人閱讀 36,988評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎铺呵,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體隧熙,經(jīng)...
    沈念sama閱讀 43,476評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡片挂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,948評(píng)論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了贞盯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片音念。...
    茶點(diǎn)故事閱讀 38,064評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖躏敢,靈堂內(nèi)的尸體忽然破棺而出闷愤,到底是詐尸還是另有隱情,我是刑警寧澤件余,帶...
    沈念sama閱讀 33,712評(píng)論 4 323
  • 正文 年R本政府宣布讥脐,位于F島的核電站,受9級(jí)特大地震影響啼器,放射性物質(zhì)發(fā)生泄漏旬渠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,261評(píng)論 3 307
  • 文/蒙蒙 一端壳、第九天 我趴在偏房一處隱蔽的房頂上張望告丢。 院中可真熱鬧,春花似錦损谦、人聲如沸岖免。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,264評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)颅湘。三九已至,卻和暖如春栗精,著一層夾襖步出監(jiān)牢的瞬間栅炒,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,486評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工术羔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赢赊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,511評(píng)論 2 354
  • 正文 我出身青樓级历,卻偏偏與公主長(zhǎng)得像释移,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寥殖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,802評(píng)論 2 345

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