免费A级毛片无码专区网站-成人国产精品视频一区二区-啊 日出水了 用力乖乖在线-国产黑色丝袜在线观看下-天天操美女夜夜操美女-日韩网站在线观看中文字幕-AV高清hd片XXX国产-亚洲av中文字字幕乱码综合-搬开女人下面使劲插视频

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

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

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

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

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

經(jīng)驗總結(jié)擴展閱讀