Go?channel結(jié)構(gòu)體源碼和讀寫和關(guān)閉過程詳解
- 簡而言之,channel維護了一個帶指針的接受和發(fā)送的隊列,其中包含mutex鎖保證并發(fā)安全,數(shù)據(jù)類型,元素個數(shù),元素大小,channel狀態(tài)
- 然后讀寫操作,先看隊列是否可以取出,然后看緩沖區(qū),最后放入接受/發(fā)送隊列
- 關(guān)閉就是喚醒所有g(shù)oroutine然后將他們的標志位設(shè)為1,表示關(guān)閉,以后有人訪問就是nil
結(jié)構(gòu)體源碼
type hchan struct { qcount uint // 當前隊列中元素的數(shù)量 dataqsiz uint // 緩沖區(qū)大小,即可以緩存的元素數(shù)量 buf unsafe.Pointer // 指向隊列的緩沖區(qū) elemsize uint16 // 每個元素的大小 closed uint32 // channel 是否已關(guān)閉的標志 elemtype *_type // channel 中元素的類型 sendx uint // 下一次發(fā)送元素的位置 recvx uint // 下一次接收元素的位置 recvq waitq // 等待接收的 goroutine 隊列 sendq waitq // 等待發(fā)送的 goroutine 隊列 lock mutex // 用于保護 channel 的互斥鎖 }
發(fā)送數(shù)據(jù)
當一個 goroutine 要向 channel 中發(fā)送數(shù)據(jù)時,它會執(zhí)行 chansend
函數(shù)。
- 這個函數(shù)首先會對 channel 進行加鎖,然后判斷是否有等待接收的 goroutine
- 如果有,則直接將數(shù)據(jù)發(fā)送給它;否則,如果緩沖區(qū)未滿,則將數(shù)據(jù)放入緩沖區(qū),隊列中元素數(shù)量加一;
- 如果隊列已滿,則將當前 goroutine 加入等待發(fā)送的 goroutine 隊列中,并阻塞它,等待其他 goroutine 接收數(shù)據(jù)。
接受數(shù)據(jù)
當一個 goroutine 要從 channel 中接收數(shù)據(jù)時,它會執(zhí)行 src/runtime/chan.go
中的 chanrecv
函數(shù)。
- 這個函數(shù)也會對 channel 進行加鎖,然后判斷是否有等待發(fā)送的 goroutine,如果有,則直接從它那里接收數(shù)據(jù);
- 否則,如果緩沖區(qū)元素的數(shù)量大于 0,則從緩沖區(qū)中取出一個元素,并將隊列中元素數(shù)量減一。
- 如果緩沖區(qū)為空,則將當前 goroutine 加入等待接收的 goroutine 隊列中,并阻塞它,等待其他 goroutine 發(fā)送數(shù)據(jù)。
關(guān)閉channel
當一個 goroutine 要關(guān)閉 channel 時,它會執(zhí)行 src/runtime/chan.go
中的 closechan
函數(shù)。
- 這個函數(shù)會對 channel 進行加鎖,然后將
closed
標志置為 1,表示 channel 已經(jīng)關(guān)閉。 - 然后遍歷等待發(fā)送和等待接收的 goroutine 隊列,將它們?nèi)繂拘?,并返回一個特殊的值來表示 channel 已經(jīng)關(guān)閉。
到此這篇關(guān)于Go channel結(jié)構(gòu)體源碼和讀寫和關(guān)閉過程的文章就介紹到這了,更多相關(guān)go channel結(jié)構(gòu)體源碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
golang?chan傳遞數(shù)據(jù)的性能開銷詳解
這篇文章主要為大家詳細介紹了Golang中chan在接收和發(fā)送數(shù)據(jù)時因為“復制”而產(chǎn)生的開銷,文中的示例代碼講解詳細,感興趣的小伙伴可以了解下2024-01-01Go語言遍歷map實現(xiàn)(訪問map中的每一個鍵值對)
這篇文章主要介紹了Go語言遍歷map實現(xiàn)(訪問map中的每一個鍵值對),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2021-01-01