Go 語言中的select語句詳解及工作原理
Go 語言中的 select 是做什么的
在 Go 語言中,select
語句是用于處理多個通道(channel)操作的一種控制結(jié)構(gòu)。它類似于 switch
語句,但專門用于并發(fā)編程,允許 Goroutine 在多個通道上等待操作(發(fā)送或接收),并在某個通道就緒時執(zhí)行對應(yīng)的分支。select
是 Go 并發(fā)模型中的核心特性之一,與通道和 Goroutine 緊密相關(guān)。
基本功能
select
的主要作用是:
- 多路復(fù)用通道:同時監(jiān)聽多個通道的讀寫操作。
- 非阻塞選擇:當(dāng)多個通道中有任意一個就緒時,執(zhí)行對應(yīng)的邏輯;如果沒有通道就緒,可以執(zhí)行默認(rèn)分支(如果有)。
- 并發(fā)協(xié)調(diào):幫助 Goroutine 在不同的通信場景中協(xié)調(diào)行為。
語法
select { case <-channel1: // 從 channel1 接收數(shù)據(jù)時的處理邏輯 case channel2 <- value: // 向 channel2 發(fā)送數(shù)據(jù)時的處理邏輯 case v := <-channel3: // 從 channel3 接收數(shù)據(jù)并賦值給 v 的處理邏輯 default: // 所有通道都未就緒時的默認(rèn)邏輯(可選) }
- 每個
case
表示一個通道操作(發(fā)送或接收)。 default
是可選的,表示當(dāng)所有通道都未就緒時執(zhí)行的邏輯。
工作原理
等待通道就緒:
select
會阻塞當(dāng)前 Goroutine,直到某個case
中的通道操作可以執(zhí)行。- 如果多個通道同時就緒,
select
會隨機選擇一個case
執(zhí)行(避免饑餓問題)。
非阻塞行為:
- 如果提供了
default
分支,且沒有通道就緒,select
會立即執(zhí)行default
而不會阻塞。
空 select:
- 如果
select
中沒有case
,會永久阻塞(類似于for {}
)。
示例
示例 1:監(jiān)聽多個通道
package main import ( "fmt" "time" ) func main() { ch1 := make(chan string) ch2 := make(chan string) go func() { time.Sleep(1 * time.Second) ch1 <- "from ch1" }() go func() { time.Sleep(2 * time.Second) ch2 <- "from ch2" }() select { case msg1 := <-ch1: fmt.Println("Received:", msg1) case msg2 := <-ch2: fmt.Println("Received:", msg2) } }
- 輸出:
Received: from ch1
- 說明:
ch1
在 1 秒后就緒,比ch2
(2 秒)快,因此執(zhí)行ch1
的分支。
示例 2:帶默認(rèn)分支
package main import ( "fmt" ) func main() { ch := make(chan string) select { case msg := <-ch: fmt.Println("Received:", msg) default: fmt.Println("No message received") } }
- 輸出:
No message received
- ???????說明:由于
ch
沒有數(shù)據(jù)就緒,select
執(zhí)行default
分支。
示例 3:發(fā)送和接收結(jié)合
package main import ( "fmt" "time" ) func main() { ch1 := make(chan string, 1) ch2 := make(chan string, 1) select { case ch1 <- "to ch1": fmt.Println("Sent to ch1") case msg := <-ch2: fmt.Println("Received from ch2:", msg) default: fmt.Println("Nothing happened") } }
- 輸出:
Sent to ch1
- ???????說明:
ch1
是緩沖通道,可以立即發(fā)送成功,因此執(zhí)行發(fā)送分支。
示例 4:超時控制
package main import ( "fmt" "time" ) func main() { ch := make(chan string) select { case msg := <-ch: fmt.Println("Received:", msg) case <-time.After(2 * time.Second): fmt.Println("Timeout after 2 seconds") } }
- 輸出:
Timeout after 2 seconds
- ???????說明:
time.After
創(chuàng)建一個定時器通道,2 秒后就緒,模擬超時邏輯。
常見用途
多路復(fù)用:
在多個通道之間選擇就緒的通道,避免逐一輪詢。
超時處理:
使用 time.After
實現(xiàn)操作超時。
非阻塞檢查:
通過 default
分支檢查通道是否就緒。
協(xié)調(diào) Goroutine:
在并發(fā)任務(wù)中,根據(jù)通道狀態(tài)決定下一步操作。
注意事項
隨機選擇:
當(dāng)多個 case
同時就緒時,select
隨機選擇一個執(zhí)行,而不是按順序。
阻塞性:
沒有 default
時,select
會阻塞直到某個通道就緒。
空 select:
select {}
這會永久阻塞,通常用于主 Goroutine 等待。
通道關(guān)閉:
如果某個通道已關(guān)閉,接收操作會立即返回零值,可能需要額外的邏輯判斷。
總結(jié)
- 是什么:
select
是 Go 中用于處理多通道操作的并發(fā)控制語句。 - 做什么:監(jiān)聽多個通道,選擇就緒的通道執(zhí)行對應(yīng)邏輯,支持超時和非阻塞操作。
- 為什么用:簡化并發(fā)編程,提高代碼效率和可讀性。
到此這篇關(guān)于Go 語言中的select是做什么的的文章就介紹到這了,更多相關(guān)Go select內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
教你一分鐘配置好Go語言開發(fā)環(huán)境(多種操作系統(tǒng))
在這篇文章中,我們從頭到尾一步步指導(dǎo)你配置Golang開發(fā)環(huán)境,并編寫你的第一個"Hello,?World!"程序,我們詳細(xì)解釋了在多種操作系統(tǒng)(包括Windows、Linux和macOS)下的安裝過程、環(huán)境變量設(shè)置以及如何驗證安裝是否成功2023-09-09golang常用庫之操作數(shù)據(jù)庫的orm框架-gorm基本使用詳解
這篇文章主要介紹了golang常用庫之操作數(shù)據(jù)庫的orm框架-gorm基本使用,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10