go channel 實(shí)現(xiàn)原理

先看下源碼,源碼位于src/runtime/chan.go中

type hchan struct {
    qcount   uint           // total data in the queue
    dataqsiz uint           // size of the circular queue
    buf      unsafe.Pointer // points to an array of dataqsiz elements
    elemsize uint16
    closed   uint32
    elemtype *_type // element type
    sendx    uint   // send index
    recvx    uint   // receive index
    recvq    waitq  // list of recv waiters
    sendq    waitq  // list of send waiters

    // lock protects all fields in hchan, as well as several
    // fields in sudogs blocked on this channel.
    //
    // Do not change another G's status while holding this lock
    // (in particular, do not ready a G), as this can deadlock
    // with stack shrinking.
    lock mutex
}
type waitq struct {
    first *sudog
    last  *sudog
}
type sudog struct {
    // The following fields are protected by the hchan.lock of the
    // channel this sudog is blocking on. shrinkstack depends on
    // this for sudogs involved in channel ops.

    g *g

    // isSelect indicates g is participating in a select, so
    // g.selectDone must be CAS'd to win the wake-up race.
    isSelect bool
    next     *sudog
    prev     *sudog
    elem     unsafe.Pointer // data element (may point to stack)

    // The following fields are never accessed concurrently.
    // For channels, waitlink is only accessed by g.
    // For semaphores, all fields (including the ones above)
    // are only accessed when holding a semaRoot lock.

    acquiretime int64
    releasetime int64
    ticket      uint32
    parent      *sudog // semaRoot binary tree
    waitlink    *sudog // g.waiting list or semaRoot
    waittail    *sudog // semaRoot
    c           *hchan // channel
}

qcount uint // 當(dāng)前隊(duì)列中剩余元素個數(shù)
dataqsiz uint // 環(huán)形隊(duì)列長度涡驮,即緩沖區(qū)的大小评架,即make(chan T,N),N.
buf unsafe.Pointer // 環(huán)形隊(duì)列指針
elemsize uint16 // 每個元素的大小
closed uint32 // 表示當(dāng)前通道是否處于關(guān)閉狀態(tài)夭坪。創(chuàng)建通道后,該字段設(shè)置為0过椎,即通道打開; 通過調(diào)用close將其設(shè)置為1室梅,通道關(guān)閉。
elemtype *_type // 元素類型疚宇,用于數(shù)據(jù)傳遞過程中的賦值亡鼠;
sendx uint和recvx uint是環(huán)形緩沖區(qū)的狀態(tài)字段,它指示緩沖區(qū)的當(dāng)前索引 - 支持?jǐn)?shù)組敷待,它可以從中發(fā)送數(shù)據(jù)和接收數(shù)據(jù)间涵。
recvq waitq // 等待讀消息的goroutine隊(duì)列
sendq waitq // 等待寫消息的goroutine隊(duì)列
lock mutex // 互斥鎖,為每個讀寫操作鎖定通道榜揖,因?yàn)榘l(fā)送和接收必須是互斥操作勾哩。
這里sudog代表goroutine。
如創(chuàng)建帶緩沖的通道:ch := make(chan int, 3)举哟,思劳,底層的數(shù)據(jù)模型如下圖:


image.png

向channel中寫入數(shù)據(jù)
ch <- 3。底層hchan數(shù)據(jù)流程如圖

image.png

image.png

發(fā)送操作流程:
1.鎖定整個通道結(jié)構(gòu)妨猩。
2.確定寫入潜叛。如果recvq不為空,嘗試recvq從等待隊(duì)列中等待goroutine册赛,然后將元素直接寫入goroutine钠导。
3.如果recvq為空,則確定緩沖區(qū)是否可用森瘪,如果可用牡属,則從當(dāng)前goroutine復(fù)制數(shù)據(jù)到緩沖區(qū)。
4.如果緩沖區(qū)已滿扼睬,則要寫入的元素將保存在當(dāng)前正在執(zhí)行的goroutine的結(jié)構(gòu)中逮栅,并且當(dāng)前goroutine將在sendq中排隊(duì)并從運(yùn)行時掛起悴势。
5.寫入完成釋放鎖。
image.png

從channel中讀取數(shù)據(jù)
ch <- 3措伐,底層hchan數(shù)據(jù)流程圖:
image.png

image.png

讀取操作概要:
1.先獲取channel全局鎖特纤。
2.嘗試從sendq等待隊(duì)列中獲取等待的goroutine。
3.如果有等待的goroutine侥加,且沒有緩沖區(qū)捧存,取出goroutine并讀取數(shù)據(jù),然后喚醒這個goroutine担败,結(jié)束讀取釋放鎖昔穴。
4.如果有等待的goroutine,且有緩沖區(qū)(緩沖區(qū)已滿)提前,從緩沖區(qū)隊(duì)首取出數(shù)據(jù)吗货,再從sendq中取出一個goroutine,將goroutine中的數(shù)據(jù)取出存入buf隊(duì)尾狈网,結(jié)束讀取釋放鎖宙搬。
5.如果沒有等待的goroutine,且緩沖區(qū)有數(shù)據(jù)拓哺,直接讀取緩沖區(qū)數(shù)據(jù)勇垛,結(jié)束讀取釋放鎖。
6.如果沒有等待的goroutine拓售,且沒有緩沖區(qū)或緩沖區(qū)為空窥摄,則當(dāng)前goroutine加入到recvq排隊(duì),進(jìn)入睡眠础淤,等待被寫的goroutine喚醒,結(jié)束讀取釋放鎖哨苛。
流程圖:
image.png

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鸽凶,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子建峭,更是在濱河造成了極大的恐慌玻侥,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亿蒸,死亡現(xiàn)場離奇詭異凑兰,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)边锁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門姑食,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人茅坛,你說我怎么就攤上這事音半。” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵曹鸠,是天一觀的道長煌茬。 經(jīng)常有香客問我,道長彻桃,這世上最難降的妖魔是什么坛善? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮邻眷,結(jié)果婚禮上浑吟,老公的妹妹穿的比我還像新娘。我一直安慰自己耗溜,他們只是感情好组力,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著抖拴,像睡著了一般燎字。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上阿宅,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天候衍,我揣著相機(jī)與錄音,去河邊找鬼洒放。 笑死蛉鹿,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的往湿。 我是一名探鬼主播妖异,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼领追!你這毒婦竟也來了他膳?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤绒窑,失蹤者是張志新(化名)和其女友劉穎棕孙,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體些膨,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蟀俊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了订雾。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肢预。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖葬燎,靈堂內(nèi)的尸體忽然破棺而出误甚,到底是詐尸還是另有隱情缚甩,我是刑警寧澤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布窑邦,位于F島的核電站擅威,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏冈钦。R本人自食惡果不足惜郊丛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞧筛。 院中可真熱鬧厉熟,春花似錦、人聲如沸较幌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽乍炉。三九已至绢片,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間岛琼,已是汗流浹背底循。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留槐瑞,地道東北人熙涤。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像困檩,于是被迫代替她去往敵國和親祠挫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354