国产精品免费嫩草研究院|无遮羞动漫在线观看AV|国产麻豆精品传媒AV国产在线|村在线观看|寂寞情人1正版|韩国床震韩国床震古|精品系列专区久久

golang channel底層結(jié)構(gòu)和實(shí)現(xiàn)

一、介紹Golang 設(shè)計(jì)模式: 不要通過(guò)共享內(nèi)存來(lái)通信,而要通過(guò)通信實(shí)現(xiàn)內(nèi)存共享
channel是基于通信順序模型(communication sequential processes, CSP)的并發(fā)模式,可以讓一個(gè) goroutine 發(fā)送特定值到另一個(gè) goroutine 的通信機(jī)制
channel中的數(shù)據(jù)遵循先入先出(First In First Out)的規(guī)則,保證收發(fā)數(shù)據(jù)的順序
二、結(jié)構(gòu)channel的源碼在runtime包下的chan.go文件, 參見chan.go
以下時(shí)channel的部分結(jié)構(gòu):
type hchan struct { qcountuint dataqsiz uint bufunsafe.Pointer elemsize uint16 closeduint32 elemtype *_type sendxuint recvxuint recvqwaitq sendqwaitq lock mutex}type waitq struct { first *sudog last*sudog}其中:
qcount: 隊(duì)列中剩余的元素個(gè)數(shù)dataqsiz: 環(huán)形隊(duì)列長(zhǎng)度,即可以存放的元素個(gè)數(shù), make初始化時(shí)指定buf: 緩存區(qū),實(shí)際上就是環(huán)形隊(duì)列(有環(huán)形隊(duì)列就有緩沖區(qū),否則沒有緩沖區(qū)),指向環(huán)形隊(duì)列首部的指針,基于環(huán)形隊(duì)列實(shí)現(xiàn),大小等于make初始化channel時(shí)指定的環(huán)形隊(duì)列長(zhǎng)度,如果make初始化channel時(shí)不指定dataqsiz,則buf=0 。只有緩沖型的channel才有bufelemsize: 每個(gè)元素的大小closed: channel關(guān)閉標(biāo)志elemtype: 元素類型sendx: 寫入數(shù)據(jù)的索引,即從哪個(gè)位置開始寫入數(shù)據(jù),取值[0, dataqsiz)recvx: 讀取數(shù)據(jù)的索引,即從哪個(gè)位置開始讀取數(shù)據(jù),取值[0, dataqsiz)recvq: 接收等待隊(duì)列,鏈表結(jié)構(gòu),長(zhǎng)度無(wú)限長(zhǎng), 讀取數(shù)據(jù)的goroutine等待隊(duì)列, 如果channel的緩沖區(qū)為空或者沒有緩沖區(qū),讀取數(shù)據(jù)的goroutine被阻塞,加入到recvq等待隊(duì)列中 。因讀阻塞的goroutine會(huì)被向channel寫入數(shù)據(jù)的goroutine喚醒sendq: 發(fā)送等待隊(duì)列,鏈表結(jié)構(gòu),長(zhǎng)度無(wú)限長(zhǎng), 寫入數(shù)據(jù)的goroutine等待隊(duì)列, 如果channel的緩沖區(qū)為滿或者沒有緩沖區(qū),寫入數(shù)據(jù)的goroutine被阻塞,加入到sendq等待隊(duì)列中 。因?qū)懽枞膅oroutine會(huì)被從channel讀取數(shù)據(jù)的goroutine喚醒lock: 并發(fā)控制鎖, 同一時(shí)刻,只允許一個(gè), channel不允許并發(fā)讀寫
1 結(jié)構(gòu)圖

golang channel底層結(jié)構(gòu)和實(shí)現(xiàn)

文章插圖
其中:
環(huán)形隊(duì)列中的0表示沒有數(shù)據(jù),1表示有數(shù)據(jù); G表示一個(gè)goroutinedataqsiz表示環(huán)形隊(duì)列的長(zhǎng)度為6, 即可緩存6個(gè)元素buf指向環(huán)形隊(duì)列首部,此時(shí)還可以緩存2個(gè)元素qcount表示環(huán)形隊(duì)列中有4個(gè)元素sendx表示下一個(gè)發(fā)送的數(shù)據(jù)在環(huán)形隊(duì)列index=5的位置寫入,取值[0, 6)recvx表示從環(huán)形隊(duì)列index=1的位置讀取數(shù)據(jù),取值[0, 6)sendq, recvq: 虛線表示,此時(shí)轉(zhuǎn)態(tài)下的channel可能有等待隊(duì)列三、channel的創(chuàng)建1 聲明channel類型
//同時(shí)讀寫的channelvar 變量 chan 類型//只能寫入數(shù)據(jù)的channelvar 變量 chan<- 類型//只能讀取數(shù)據(jù)的channelvar 變量 <-chan 類型 其中:
類型:channel內(nèi)的數(shù)據(jù)類型,golang支持的合法類型
聲明的channel此時(shí)還是nil,需要配合make函數(shù)初始化之后才能使用
2 創(chuàng)建channel
//無(wú)緩沖的channel變量 := make(chan 數(shù)據(jù)類型)//有緩沖的channel變量 := make(chan 數(shù)據(jù)類型, dataqsiz)
四、向channel發(fā)送數(shù)據(jù)1 發(fā)送數(shù)據(jù)的格式
變量 <- 值2 寫數(shù)據(jù)的過(guò)程
1) 流程圖如下:
golang channel底層結(jié)構(gòu)和實(shí)現(xiàn)

文章插圖
 
其中:
G表示一個(gè)goroutine虛線表示sendq中堵塞的G被喚醒的流程,如果G沒有被喚醒,則一直堵塞下去,此時(shí)關(guān)閉channel,會(huì)觸發(fā)panic2) 過(guò)程描述:
1) 如果channel是nil(沒有初始化), 發(fā)送數(shù)據(jù)則一直會(huì)堵塞,這是一個(gè)BUG2) 如果等待接收隊(duì)列recvq 不為空,說(shuō)明沒有緩沖區(qū)或者緩沖區(qū)沒有數(shù)據(jù),直接從recvq取出一個(gè)G數(shù)據(jù)寫入,把G喚醒,結(jié)束發(fā)送過(guò)程3) 如果等待接收隊(duì)列recvq為空,且緩沖區(qū)有空位,那么就直接將數(shù)據(jù)寫入緩沖區(qū)sendx位置, sendx++, qcount++, 結(jié)束發(fā)送過(guò)程4) 如果等待接收隊(duì)列recvq為空,緩沖區(qū)沒有空位,將數(shù)據(jù)寫入G,然后把G放到等待發(fā)送隊(duì)列sendq中進(jìn)行阻塞,等待被喚醒, 結(jié)束發(fā)送過(guò)程 。當(dāng)被喚醒的時(shí)候,需要寫入的數(shù)據(jù)已經(jīng)被讀取出來(lái),且已經(jīng)完成了寫入操作

經(jīng)驗(yàn)總結(jié)擴(kuò)展閱讀