網(wǎng)站首頁 編程語言 正文
1. select的使用
select 是 Go 提供的 IO 多路復(fù)用機(jī)制,可以用多個(gè) case 同時(shí)監(jiān)聽多個(gè) channl 的讀寫狀態(tài):
- case: 可以監(jiān)聽 channl 的讀寫信號(hào)
- default:聲明默認(rèn)操作,有該字段的 select 不會(huì)阻塞
select { case chan <-: // TODO case <- chan: // TODO default: // TODO }
2. 底層原理
- 每一個(gè) case 對(duì)應(yīng)的 channl 都會(huì)被封裝到一個(gè)結(jié)構(gòu)體中;
- 當(dāng)?shù)谝淮螆?zhí)行到 select 時(shí),會(huì)鎖住所有的 channl 并且,打亂 case 結(jié)構(gòu)體的順序;
- 按照打亂的順序遍歷,如果有就緒的信號(hào),就直接走對(duì)應(yīng) case 的代碼段,之后跳出 select;
- 如果沒有就緒的代碼段,但是有 default 字段,那就走 default 的代碼段,之后跳出 select;
- 如果沒有 default,那就將當(dāng)前 goroutine 加入所有 channl 的對(duì)應(yīng)等待隊(duì)列;
- 當(dāng)某一個(gè)等待隊(duì)列就緒時(shí),再次鎖住所有的 channl,遍歷一遍,將所有等待隊(duì)列中的 goroutine 取出,之后執(zhí)行就緒的代碼段,跳出select。
3. 數(shù)據(jù)結(jié)構(gòu)
每一個(gè) case 對(duì)應(yīng)的數(shù)據(jù)結(jié)構(gòu)如下:
type scase struct { c *hchan // chan elem unsafe.Pointer // 讀或者寫的緩沖區(qū)地址 kind uint16 //case語句的類型,是default、傳值寫數(shù)據(jù)(channel <-) 還是 取值讀數(shù)據(jù)(<- channel) pc uintptr // race pc (for race detector / msan) releasetime int64 }
4. 幾種常見 case
學(xué)習(xí)了 select 的使用與原理,我們就能更輕松地分辨不同情況下的輸出情況了。
case 1
package main import ( "fmt" "time" ) func main() { chan1 := make(chan int) chan2 := make(chan int) go func() { chan1 <- 1 time.Sleep(5 * time.Second) }() go func() { chan2 <- 1 time.Sleep(5 * time.Second) }() select { case <- chan1: fmt.Println("chan1") case <- chan2: fmt.Println("chan2") default: fmt.Println("default") } }
三種輸出都有可能。
case2
package main import ( "fmt" "time" ) func main() { chan1 := make(chan int) chan2 := make(chan int) select { case <- chan1: fmt.Println("chan1") case <- chan2: fmt.Println("chan2") } fmt.Println("main exit.") }
上述程序會(huì)一直阻塞。
case3
package main import ( "fmt" ) func main() { chan1 := make(chan int) chan2 := make(chan int) go func() { close(chan1) }() go func() { close(chan2) }() select { case <- chan1: fmt.Println("chan1") case <- chan2: fmt.Println("chan2") } fmt.Println("main exit.") }
隨機(jī)執(zhí)行1或者2.
case4
package main func main() { select { } }
對(duì)于空的 select 語句,程序會(huì)被阻塞,確切的說是當(dāng)前協(xié)程被阻塞,同時(shí) Go 自帶死鎖檢測(cè)機(jī)制,當(dāng)發(fā)現(xiàn)當(dāng)前協(xié)程再也沒有機(jī)會(huì)被喚醒時(shí),則會(huì)發(fā)生 panic。所以上述程序會(huì) panic。
原文鏈接:https://juejin.cn/post/7123037385419407374
相關(guān)推薦
- 2022-08-28 linux應(yīng)用參數(shù)保存與配置
- 2023-12-23 uni-app消息推送uni-push使用
- 2021-12-28 vscode搭建go開發(fā)環(huán)境案例詳解_Golang
- 2024-02-26 IDEA隱藏指定文件/文件夾
- 2022-04-01 ?python中pandas讀取csv文件?時(shí)如何省去csv.reader()操作指定列步驟_pyt
- 2022-05-01 pandas中關(guān)于apply+lambda的應(yīng)用_python
- 2022-11-12 基于Python制作一個(gè)匯率換算程序_python
- 2022-04-29 Go語言中的并發(fā)goroutine底層原理_Golang
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲(chǔ)小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯(cuò)誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動(dòng)態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對(duì)象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊(duì)列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支