go version:1.12.5
文件 :src/runtime/chan.go
先分析下管道的結(jié)構(gòu)體
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 mutex
}
qcount
當(dāng)前隊(duì)列中剩余的元素個(gè)數(shù)dataqsize
環(huán)形隊(duì)列長(zhǎng)度,即可以存放的元素個(gè)數(shù)buf
指向隊(duì)列的內(nèi)存,環(huán)形隊(duì)列的指針elemsize
每個(gè)元素的大小closed
標(biāo)識(shí)關(guān)閉狀態(tài)elemtype
元素類(lèi)型sendx
隊(duì)列下標(biāo),指示元素寫(xiě)入時(shí)存放到隊(duì)列中的位置,即隊(duì)尾recvx
隊(duì)列下標(biāo),指示下一個(gè)被讀取的元素在隊(duì)列中的位置,即隊(duì)首recvq
等待讀消息的協(xié)程隊(duì)列,讀取數(shù)據(jù)時(shí),如果管道緩沖區(qū)為空或沒(méi)有緩沖區(qū),則當(dāng)前協(xié)程會(huì)被阻塞,并被加入recvq隊(duì)列.sendq
等待寫(xiě)消息的協(xié)程隊(duì)列,向管道寫(xiě)入數(shù)據(jù)時(shí),如果管道緩沖區(qū)已滿或沒(méi)有緩沖區(qū),則當(dāng)前協(xié)程會(huì)被阻塞,并被加入sendq隊(duì)列.lock mutex
互斥鎖, chan不允許并發(fā)讀寫(xiě),即一個(gè)管道同時(shí)僅允許被一個(gè)協(xié)程讀寫(xiě).注意:
sendq
和recvq
中的至少一個(gè)為空狼渊,但使用select
發(fā)送和接收的無(wú)緩沖通道上阻塞了單個(gè)goroutine
的情況除外躏筏,在這種情況下,sendq的長(zhǎng)度而recvq僅受select語(yǔ)句的大小限制.
即:同一個(gè)協(xié)程使用select語(yǔ)句向管道一邊寫(xiě)入一邊讀取,此時(shí)協(xié)程會(huì)分別位于兩個(gè)隊(duì)列
qcount> 0表示recvq為空.
qcount <dataqsiz表示sendq為空.
看圖中結(jié)構(gòu)體數(shù)據(jù)變化
執(zhí)行邏輯
-
向channel寫(xiě)入數(shù)據(jù)
image.png -
從channel中讀取數(shù)據(jù)
image.png
參考《GO專家編程》