Go開(kāi)發(fā) Channel徹底研究之Select選擇規(guī)則
從左往右,從上往下
對(duì)于select的求值,一條case中,從左往右求值;多條case,從上往下,下面舉幾個(gè)例子說(shuō)明:
代碼分析
這段代碼設(shè)計(jì)的也比較巧妙,調(diào)試看出getChan先于getNumber執(zhí)行,說(shuō)明一條case中是從左往右求值的;同理,多條case是從上往下執(zhí)行。
但是有一個(gè)問(wèn)題,我們發(fā)現(xiàn)ch2和ch4都是nil,簡(jiǎn)化形式如下:
select的case中允許這樣寫(xiě),但相當(dāng)于沒(méi)有寫(xiě),永遠(yuǎn)不會(huì)執(zhí)行。除此外,select中還有很多奇怪的使用方式,再比如:
沒(méi)有接收方代碼,但是依然也不會(huì)錯(cuò)。
具體運(yùn)行規(guī)則
一、在執(zhí)行select語(yǔ)句時(shí),運(yùn)行時(shí)系統(tǒng)會(huì)自上而下判斷每個(gè)case中的發(fā)送或接收操作是否可以被立即執(zhí)行,這里的立即執(zhí)行的意思是當(dāng)前goroutine不會(huì)因此操作而阻塞。
要點(diǎn):case中的語(yǔ)句要能立即執(zhí)行
二、當(dāng)發(fā)現(xiàn)第一個(gè)滿足條件的case時(shí),運(yùn)行時(shí)系統(tǒng)就會(huì)執(zhí)行該case所包含的語(yǔ)句,同時(shí),其它c(diǎn)ase也會(huì)被忽略。
要點(diǎn):只執(zhí)行一個(gè)case
三、如果同時(shí)有多個(gè)case滿足條件,那么運(yùn)行時(shí)會(huì)通過(guò)一個(gè)偽隨機(jī)的算法決定哪一個(gè)case將會(huì)執(zhí)行。
要點(diǎn):多個(gè)case同時(shí)滿足,使用算法選擇一個(gè)
代碼分析
這段代碼也很巧妙,驗(yàn)證了多個(gè)case同時(shí)滿足條件時(shí),如何進(jìn)行隨機(jī)選擇。
輸出:
3 2 2 2 3
2 1 1 1 2
1 1 3 2 1
可以看出,作者電腦上每次顯示的都是一些隨機(jī)選擇。
四、如果所有的case都不能立即執(zhí)行,且沒(méi)有default,那么select會(huì)阻塞,直到某個(gè)接收或發(fā)送的case操作能立即執(zhí)行。
代碼分析
select等待兩個(gè)channel,由于都延時(shí)且沒(méi)有default,所以select阻塞等待。1s后ch1可以立即執(zhí)行,因此打印10,select也退出選擇。
五、如果所有通道都是nil且沒(méi)有default,且會(huì)發(fā)生死鎖
select和for的配合
select和for的搭配有很多問(wèn)題,本篇只說(shuō)明一個(gè)問(wèn)題:
select的case中可以使用break,但是只跳出select(區(qū)域1),如果想跳出for循環(huán)(區(qū)域2),需要一些輔助技巧。
總結(jié)
介紹了select的一些基本選擇規(guī)則,也是需要背誦的知識(shí)點(diǎn)。