自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Go開(kāi)發(fā) Channel徹底研究之Select選擇規(guī)則

開(kāi)發(fā) 前端
在執(zhí)行select語(yǔ)句時(shí),運(yùn)行時(shí)系統(tǒng)會(huì)自上而下判斷每個(gè)case中的發(fā)送或接收操作是否可以被立即執(zhí)行,這里的立即執(zhí)行的意思是當(dāng)前goroutine不會(huì)因此操作而阻塞。

從左往右,從上往下

對(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中允許這樣寫(xiě),但相當(dāng)于沒(méi)有寫(xiě),永遠(yuǎn)不會(huì)執(zhí)行。除此外,select中還有很多奇怪的使用方式,再比如:

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

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

沒(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è)

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í)行,且沒(méi)有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í)且沒(méi)有default,所以select阻塞等待。1s后ch1可以立即執(zhí)行,因此打印10,select也退出選擇。

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

// ch1 == nil
var ch1 chan int
select {
case <-ch1:
fmt.Println("hello")
// 沒(méi)有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)。

責(zé)任編輯:武曉燕 來(lái)源: 今日頭條
相關(guān)推薦

2023-03-09 09:06:13

ChanneGo開(kāi)發(fā)

2023-05-29 09:25:38

GolangSelect

2023-07-13 08:06:05

應(yīng)用協(xié)程阻塞

2021-10-11 11:58:41

Channel原理recvq

2021-10-09 19:05:06

channelGo原理

2024-09-06 10:48:13

2017-04-11 14:45:22

機(jī)器學(xué)習(xí)學(xué)習(xí)平臺(tái)大數(shù)據(jù)平臺(tái)

2020-12-27 10:15:44

Go語(yǔ)言channel管道

2021-09-01 18:38:59

Goselectdefault

2023-07-27 13:46:10

go開(kāi)源項(xiàng)目

2019-12-10 13:55:10

Go指針存儲(chǔ)

2022-02-22 08:55:29

SelectPoll/ Epoll

2024-06-19 10:08:34

GoChannel工具

2023-11-03 18:03:54

Web應(yīng)用Python

2019-10-17 09:00:00

GoRust編程語(yǔ)言

2011-08-12 09:35:05

javascript

2020-06-22 07:18:21

Java語(yǔ)言開(kāi)發(fā)

2023-12-20 07:30:54

Goselect編程

2021-09-30 09:21:28

Go語(yǔ)言并發(fā)編程

2025-04-02 05:23:00

GoChannel數(shù)據(jù)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)