<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
Go中的channel 是一個佇列,遵循先進先出的原則,負責協程之間的通訊(Go 語言提倡不要通過共用記憶體來通訊,而要通過通訊來實現記憶體共用,CSP(Communicating Sequential Process)並行模型,就是通過 goroutine 和 channel 來實現的)
停止訊號監聽
定時任務
生產方和消費方解耦
控制並行數
通過var宣告或者make函數建立的channel變數是一個儲存在函數棧幀上的指標,佔用8個位元組,指向堆上的hchan結構體
原始碼包中src/runtime/chan.go
定義了hchan的資料結構:
hchan結構體:
type hchan struct { closed uint32 // channel是否關閉的標誌 elemtype *_type // channel中的元素型別 // channel分為無緩衝和有緩衝兩種。 // 對於有緩衝的channel儲存資料,使用了 ring buffer(環形緩衝區) 來快取寫入的資料,本質是迴圈陣列 // 為啥是迴圈陣列?普通陣列不行嗎,普通陣列容量固定更適合指定的空間,彈出元素時,普通陣列需要全部都前移 // 當下標超過陣列容量後會回到第一個位置,所以需要有兩個欄位記錄當前讀和寫的下標位置 buf unsafe.Pointer // 指向底層迴圈陣列的指標(環形緩衝區) qcount uint // 迴圈陣列中的元素數量 dataqsiz uint // 迴圈陣列的長度 elemsize uint16 // 元素的大小 sendx uint // 下一次寫下標的位置 recvx uint // 下一次讀下標的位置 // 嘗試讀取channel或向channel寫入資料而被阻塞的goroutine recvq waitq // 讀等待佇列 sendq waitq // 寫等待佇列 lock mutex //互斥鎖,保證讀寫channel時不存在並行競爭問題 }
等待佇列:
雙向連結串列,包含一個頭結點和一個尾結點
每個節點是一個sudog結構體變數,記錄哪個協程在等待,等待的是哪個channel,等待傳送/接收的資料在哪裡
type waitq struct { first *sudog last *sudog } type sudog struct { g *g next *sudog prev *sudog elem unsafe.Pointer c *hchan ... }
使用 make(chan T, cap)
來建立 channel,make 語法會在編譯時,轉換為 makechan64
和 makechan
func makechan64(t *chantype, size int64) *hchan { if int64(int(size)) != size { panic(plainError("makechan: size out of range")) } return makechan(t, int(size)) }
建立channel 有兩種,一種是帶緩衝的channel,一種是不帶緩衝的channel
// 帶緩衝 ch := make(chan int, 3) // 不帶緩衝 ch := make(chan int)
建立時會做一些檢查:
建立時的策略:
傳送操作,編譯時轉換為runtime.chansend
函數
func chansend(c *hchan, ep unsafe.Pointer, block bool, callerpc uintptr) bool
阻塞式:
呼叫chansend函數,並且block=true
ch <- 10
非阻塞式:
呼叫chansend函數,並且block=false
select { case ch <- 10: ... default }
向 channel 中傳送資料時大概分為兩大塊:檢查和資料傳送,資料傳送流程如下:
如果 channel 的讀等待佇列存在接收者goroutine
如果 channel 的讀等待佇列不存在接收者goroutine
傳送操作,編譯時轉換為runtime.chanrecv
函數
func chanrecv(c *hchan, ep unsafe.Pointer, block bool) (selected, received bool)
阻塞式:
呼叫chanrecv函數,並且block=true
<ch v := <ch v, ok := <ch // 當channel關閉時,for迴圈會自動退出,無需主動監測channel是否關閉,可以防止讀取已經關閉的channel,造成讀到資料為通道所儲存的資料型別的零值 for i := range ch { fmt.Println(i) }
非阻塞式:
呼叫chanrecv函數,並且block=false
select { case <-ch: ... default }
向 channel 中接收資料時大概分為兩大塊,檢查和資料傳送,而資料接收流程如下:
如果 channel 的寫等待佇列存在傳送者goroutine
如果 channel 的寫等待佇列不存在傳送者goroutine
關閉操作,呼叫close函數,編譯時轉換為runtime.closechan
函數
close(ch)
func closechan(c *hchan)
package main import ( "fmt" "time" "unsafe" ) func main() { // ch是長度為4的帶緩衝的channel // 初始hchan結構體重的buf為空,sendx和recvx均為0 ch := make(chan string, 4) fmt.Println(ch, unsafe.Sizeof(ch)) go sendTask(ch) go receiveTask(ch) time.Sleep(1 * time.Second) } // G1是傳送者 // 當G1向ch裡傳送資料時,首先會對buf加鎖,然後將task儲存的資料copy到buf中,然後sendx++,然後釋放對buf的鎖 func sendTask(ch chan string) { taskList := []string{"this", "is", "a", "demo"} for _, task := range taskList { ch <- task //傳送任務到channel } } // G2是接收者 // 當G2消費ch的時候,會首先對buf加鎖,然後將buf中的資料copy到task變數對應的記憶體裡,然後recvx++,並釋放鎖 func receiveTask(ch chan string) { for { task := <-ch //接收任務 fmt.Println("received", task) //處理任務 } }
總結hchan結構體的主要組成部分有四個:
以上就是Go底層channel實現原理及範例詳解的詳細內容,更多關於Go channel底層原理的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45