詳解Golang中channel的實(shí)現(xiàn)
1、channel的基本概念
channel俗稱(chēng)管道,用于數(shù)據(jù)傳遞或數(shù)據(jù)共享,其本質(zhì)是一個(gè)先進(jìn)先出的隊(duì)列,使用goroutine+channel進(jìn)行數(shù)據(jù)通訊簡(jiǎn)單高效,同時(shí)也線程安全,多個(gè)goroutine可同時(shí)修改一個(gè)channel,不需要加鎖。
channel可分為三種類(lèi)型:
- 只讀channel:只能讀channel里面數(shù)據(jù),不可寫(xiě)入
- 只寫(xiě)channel:只能寫(xiě)數(shù)據(jù),不可讀
- 一般channel:可讀可寫(xiě)
2、channel的數(shù)據(jù)結(jié)構(gòu)
type hchan struct {
qcount uint // 隊(duì)列中元素個(gè)數(shù)
dataqsiz uint // 循環(huán)隊(duì)列的大小
buf unsafe.Pointer // 指向循環(huán)隊(duì)列
elemsize uint16 // 通道里面的元素大小
closed uint32 // 通道關(guān)閉的標(biāo)志
elemtype *_type // 通道元素的類(lèi)型
sendx uint // 待發(fā)送的索引,即循環(huán)隊(duì)列中的隊(duì)尾指針front
recvx uint // 待讀取的索引,即循環(huán)隊(duì)列中的隊(duì)頭指針rear
recvq waitq // 接收等待隊(duì)列
sendq waitq // 發(fā)送等待隊(duì)列
lock mutex // 互斥鎖
}3、channel的hchan結(jié)構(gòu)圖

hchan結(jié)構(gòu)體中的buf指向一個(gè)數(shù)組,用來(lái)實(shí)現(xiàn)循環(huán)隊(duì)列,sendx是循環(huán)隊(duì)列的隊(duì)尾指針,recvx是循環(huán)隊(duì)列的隊(duì)頭指針。dataqsize是緩存型通道的大小,qcount是記錄通道內(nèi)元素個(gè)數(shù)。
循環(huán)隊(duì)列一般使用空余單元法來(lái)解決隊(duì)空和隊(duì)滿時(shí)候都存在font=rear帶來(lái)的二義性問(wèn)題,但這樣會(huì)浪費(fèi)一個(gè)單元。golang的channel中是通過(guò)增加qcount字段記錄隊(duì)列長(zhǎng)度來(lái)解決二義性,一方面不會(huì)浪費(fèi)一個(gè)存儲(chǔ)單元,另一方面當(dāng)使用len函數(shù)查看隊(duì)列長(zhǎng)度時(shí)候,可以直接返回qcount字段,一舉兩得。
hchan結(jié)構(gòu)體中另一重要部分是recvq,sendq,分別存儲(chǔ)了等待從通道中接收數(shù)據(jù)的goroutine,和等待發(fā)送數(shù)據(jù)到通道的goroutine。兩者都是waitq類(lèi)型。sudog是對(duì)goroutine的一種封裝
type waitq struct {
first *sudog
last *sudog
}waitq是一個(gè)結(jié)構(gòu)體類(lèi)型,waitq和sudog構(gòu)成雙向鏈表,其中sudog是鏈表元素的類(lèi)型,waitq中first和last字段分別指向鏈表頭部的sudog,鏈表尾部的sudog。
channel 的發(fā)送和接收操作本質(zhì)上都是 “值的拷貝”,無(wú)論是從 sender goroutine 的棧到 chan buf,還是從 chan buf 到 receiver goroutine,或者是直接從 sender goroutine 到 receiver goroutine。
channel讀取寫(xiě)入流程
| 操作 | nil channel | closed channel | not nil,not closed |
|---|---|---|---|
close | panic | panic | 正常關(guān)閉 |
讀<-ch | 阻塞 | 如果channel關(guān)閉前有數(shù)據(jù),則會(huì)正常讀取到數(shù)據(jù).如果沒(méi)有數(shù)據(jù)則會(huì)讀取到對(duì)應(yīng)元素類(lèi)型的空值 | 阻塞或正常讀取數(shù)據(jù),緩沖型channel為空或非緩沖型channel等待發(fā)送者時(shí)會(huì)阻塞 |
寫(xiě)ch<- | 阻塞 | panic | 阻塞或正常寫(xiě)入數(shù)據(jù),非緩沖型channel等待接收者或緩沖型channel buf滿時(shí)會(huì)被阻塞 |
到此這篇關(guān)于詳解Golang中channel的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang channel實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go+Lua解決Redis秒殺中庫(kù)存與超賣(mài)問(wèn)題
本文主要介紹了Go+Lua解決Redis秒殺中庫(kù)存與超賣(mài)問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-03-03
詳解Golang開(kāi)啟http服務(wù)的三種方式
這篇文章主要介紹了詳解Golang開(kāi)啟http服務(wù)的三種方式,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-06-06
golang?gorm實(shí)現(xiàn)get請(qǐng)求查詢(xún)案例測(cè)試
這篇文章主要為大家介紹了golang?gorm實(shí)現(xiàn)get請(qǐng)求查詢(xún)案例測(cè)試,2022-04-04
go 代碼格式化和風(fēng)格開(kāi)發(fā)者指南
這篇文章主要為大家介紹了go 代碼格式化和風(fēng)格開(kāi)發(fā)者指南,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-09-09
淺談?dòng)肎o構(gòu)建不可變的數(shù)據(jù)結(jié)構(gòu)的方法
這篇文章主要介紹了用Go構(gòu)建不可變的數(shù)據(jù)結(jié)構(gòu)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Go語(yǔ)言常見(jiàn)設(shè)計(jì)模式之裝飾模式詳解
在?Go?語(yǔ)言中,雖然裝飾模式?jīng)]有像?Python?中應(yīng)用那么廣泛,但也有其用武之地,這篇文章我們就來(lái)一起看下裝飾模式在?Go?語(yǔ)言中的應(yīng)用吧2023-07-07
Go語(yǔ)言轉(zhuǎn)換所有字符串為大寫(xiě)或者小寫(xiě)的方法
這篇文章主要介紹了Go語(yǔ)言轉(zhuǎn)換所有字符串為大寫(xiě)或者小寫(xiě)的方法,實(shí)例分析了ToLower和ToUpper函數(shù)的使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-02-02
go語(yǔ)言interface接口繼承多態(tài)示例及定義解析
這篇文章主要為大家介紹了go語(yǔ)言interface接口繼承多態(tài)示例及定義解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04
Go初學(xué)者踩坑之go?mod?init與自定義包的使用
go?mod是go的一個(gè)模塊管理工具,用來(lái)代替?zhèn)鹘y(tǒng)的GOPATH方案,下面這篇文章主要給大家介紹了關(guān)于Go初學(xué)者踩坑之go?mod?init與自定義包的使用,需要的朋友可以參考下2022-10-10

