日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
Go開發(fā)Channel徹底研究之Select選擇規(guī)則

從左往右,從上往下

對(duì)于select的求值,一條case中,從左往右求值;多條case,從上往下,下面舉幾個(gè)例子說(shuō)明:

var ch2 chan int
var ch4 chan int
var chs = []chan int{ch2, ch4}
var numbers = []int{1, 2, 3, 4, 5}
func main() {

select {
case getChan(0) <- getNumber(2):
fmt.Println("1th case is selected")
case getChan(1) <- getNumber(3):
fmt.Println("2th case is selected")
default:
fmt.Println("default!")
}
}
func getChan(i int) chan int {
fmt.Printf("chs[%d]\n",i);
return chs[i]
}
func getNumber(i int) int {
fmt.Printf("numbers[%d]\n",i)
return numbers[i]
}

代碼分析

這段代碼設(shè)計(jì)的也比較巧妙,調(diào)試看出getChan先于getNumber執(zhí)行,說(shuō)明一條case中是從左往右求值的;同理,多條case是從上往下執(zhí)行。

但是有一個(gè)問(wèn)題,我們發(fā)現(xiàn)ch2和ch4都是nil,簡(jiǎn)化形式如下:

//ch == nil
var ch chan int

select {
case ch <- 0:
default:
fmt.Println("默認(rèn)執(zhí)行...")
}

select的case中允許這樣寫,但相當(dāng)于沒有寫,永遠(yuǎn)不會(huì)執(zhí)行。除此外,select中還有很多奇怪的使用方式,再比如:

//無(wú)緩沖通道
ch := make(chan int)

select {
case ch <- 0:
default:
fmt.Println("默認(rèn)執(zhí)行...")
}

沒有接收方代碼,但是依然也不會(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è)

chanCap := 5
ch := make(chan int, chanCap)

for i := 0; i < chanCap; i++ {
select {
case ch <- 1:
case ch <- 2:
case ch <- 3:
}
}

for i := 0; i < chanCap; i++ {
fmt.Printf("%v ", <-ch)
}

代碼分析

這段代碼也很巧妙,驗(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í)行,且沒有default,那么select會(huì)阻塞,直到某個(gè)接收或發(fā)送的case操作能立即執(zhí)行。

ch1 := make(chan int)
ch2 := make(chan int)
go func() {
time.Sleep(1 * time.Second)
ch1 <- 10
}()
go func() {
time.Sleep(1 * time.Second)
ch1 <- 20
}()
select {
case d := <-ch1:
fmt.Println(d)
case d := <-ch2:
fmt.Println(d)
}

代碼分析

select等待兩個(gè)channel,由于都延時(shí)且沒有default,所以select阻塞等待。1s后ch1可以立即執(zhí)行,因此打印10,select也退出選擇。

五、如果所有通道都是nil且沒有default,且會(huì)發(fā)生死鎖

// ch1 == nil
var ch1 chan int
select {
case <-ch1:
fmt.Println("hello")
// 沒有default
}

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)。


當(dāng)前名稱:Go開發(fā)Channel徹底研究之Select選擇規(guī)則
本文來(lái)源:http://www.dlmjj.cn/article/cdsdipi.html