<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
golang
中主推 channel
通訊。單個 channel
的通訊可以通過一個goroutine
往 channel
發資料,另外一個從channel
取資料進行。這是阻塞的,因為要想順利執行完這個步驟,需要 channel
準備好
才行,準備好
的條件如下:
1.傳送
channel
)goroutine
2.接收
channel
)goroutine
對channel
實際使用中還有如下兩個需求,這個時候就需要select
了。
channel
channel
準備好的時候,也可以往下執行。1.空select
。作用是阻塞當前goroutine
。不要用for{}
來阻塞goroutine
,因為會佔用cpu。而select{}
不會,因為當前goroutine
不會再被排程。
if len(cases) == 0 { block() }
2.設定好poll的順序。由於是同時監聽多個channel
的傳送或者接收,所以需要按照一定的順序檢視哪個channel
準備好了。如果每次採用select
中的順序檢視channel
是否準備好了,那麼只要在前面的channel
準備好的足夠快,那麼會造成後面的channel
即使準備好了,也永遠不會被執行。打亂順序的邏輯如下,採用了洗牌演演算法color{red}{洗牌演演算法}洗牌演演算法,注意此過程中會過濾掉channel為nil的case。color{red}{注意此過程中會過濾掉 channel 為 nil 的 case。}注意此過程中會過濾掉channel為nil的case。
// generate permuted order norder := 0 for i := range scases { cas := &scases[i] // Omit cases without channels from the poll and lock orders. if cas.c == nil { cas.elem = nil // allow GC continue } j := fastrandn(uint32(norder + 1)) pollorder[norder] = pollorder[j] pollorder[j] = uint16(i) norder++ }
3.設定好lock的順序。由於可能會修改channel
中的資料,所以在打算往channel
中傳送資料或者從channel
接收資料的時候,需要鎖住 channel
。而一個channel
可能被多個select
監聽,如果兩個select
對兩個channel
A和B,分別按照順序A, B和B,A上鎖,是可能會造成死鎖的,導致兩個select
都執行不下去。
所以select
中鎖住channel
的順序至關重要,解決方案是按照channel
的地址的順序鎖住channel
。因為在兩個select
中channel
有交集的時候,都是按照交集中channel
的地址順序鎖channel
。
實際排序程式碼如下,採用堆排序演演算法color{red}{堆排序演演算法}堆排序演演算法按照channel
的地址從小到大對channel
進行排序。
// sort the cases by Hchan address to get the locking order. // simple heap sort, to guarantee n log n time and constant stack footprint. for i := range lockorder { j := i // Start with the pollorder to permute cases on the same channel. c := scases[pollorder[i]].c for j > 0 && scases[lockorder[(j-1)/2]].c.sortkey() < c.sortkey() { k := (j - 1) / 2 lockorder[j] = lockorder[k] j = k } lockorder[j] = pollorder[i] } for i := len(lockorder) - 1; i >= 0; i-- { o := lockorder[i] c := scases[o].c lockorder[i] = lockorder[0] j := 0 for { k := j*2 + 1 if k >= i { break } if k+1 < i && scases[lockorder[k]].c.sortkey() < scases[lockorder[k+1]].c.sortkey() { k++ } if c.sortkey() < scases[lockorder[k]].c.sortkey() { lockorder[j] = lockorder[k] j = k continue } break } lockorder[j] = o }
4.鎖住select
中的所有channel
。要檢視channel
中的資料了。
// lock all the channels involved in the select sellock(scases, lockorder)
5.第一輪檢視是否已有準備好
的channel。如果有直接傳送資料到channel
或者從channel
接收資料。注意select
的channel
切片中,前面部分是從channel
接收資料的case,後半部分是往channel
傳送資料的case。
按照pollorder
順序檢視是否有channel
準備好了。
for _, casei := range pollorder { casi = int(casei) cas = &scases[casi] c = cas.c if casi >= nsends { sg = c.sendq.dequeue() if sg != nil { goto recv } if c.qcount > 0 { goto bufrecv } if c.closed != 0 { goto rclose } } else { if raceenabled { racereadpc(c.raceaddr(), casePC(casi), chansendpc) } if c.closed != 0 { goto sclose } sg = c.recvq.dequeue() if sg != nil { goto send } if c.qcount < c.dataqsiz { goto bufsend } } }
6.直接執行default
分支
if !block { selunlock(scases, lockorder) casi = -1 goto retc }
7.第二輪遍歷channel
。建立sudog
把當前goroutine
放到每個channel
的等待列表中去,等待channel
準備好時被喚醒。
// pass 2 - enqueue on all chans gp = getg() if gp.waiting != nil { throw("gp.waiting != nil") } nextp = &gp.waiting for _, casei := range lockorder { casi = int(casei) cas = &scases[casi] c = cas.c sg := acquireSudog() sg.g = gp sg.isSelect = true // No stack splits between assigning elem and enqueuing // sg on gp.waiting where copystack can find it. sg.elem = cas.elem sg.releasetime = 0 if t0 != 0 { sg.releasetime = -1 } sg.c = c // Construct waiting list in lock order. *nextp = sg nextp = &sg.waitlink if casi < nsends { c.sendq.enqueue(sg) } else { c.recvq.enqueue(sg) } }
8.等待被喚醒。其中gopark
的時候會釋放對所有channel
佔用的鎖。
// wait for someone to wake us up gp.param = nil // Signal to anyone trying to shrink our stack that we're about // to park on a channel. The window between when this G's status // changes and when we set gp.activeStackChans is not safe for // stack shrinking. atomic.Store8(&gp.parkingOnChan, 1) gopark(selparkcommit, nil, waitReasonSelect, traceEvGoBlockSelect, 1) gp.activeStackChans = false
9.被喚醒
channel
goroutine
的等待sudog
channel
喚醒的,並清理每個channel
上當前的goroutine
對應的sudog
sellock(scases, lockorder) gp.selectDone = 0 sg = (*sudog)(gp.param) gp.param = nil // pass 3 - dequeue from unsuccessful chans // otherwise they stack up on quiet channels // record the successful case, if any. // We singly-linked up the SudoGs in lock order. casi = -1 cas = nil caseSuccess = false sglist = gp.waiting // Clear all elem before unlinking from gp.waiting. for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { sg1.isSelect = false sg1.elem = nil sg1.c = nil } gp.waiting = nil for _, casei := range lockorder { k = &scases[casei] if sg == sglist { // sg has already been dequeued by the G that woke us up. casi = int(casei) cas = k caseSuccess = sglist.success if sglist.releasetime > 0 { caseReleaseTime = sglist.releasetime } } else { c = k.c if int(casei) < nsends { c.sendq.dequeueSudoG(sglist) } else { c.recvq.dequeueSudoG(sglist) } } sgnext = sglist.waitlink sglist.waitlink = nil releaseSudog(sglist) sglist = sgnext }
到此這篇關於詳解Golang中select的使用與原始碼分析的文章就介紹到這了,更多相關Golang select內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援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