Go 語言 select 語句
select是Go中的一個控制結(jié)構(gòu),類似于用于通信的switch語句。每個case必須是一個通信操作,要么是發(fā)送要么是接收。
select隨機執(zhí)行一個可運行的case。如果沒有case可運行,它將阻塞,直到有case可運行。一個默認(rèn)的子句應(yīng)該總是可運行的。
這里的通信,可以簡單的理解為IO(輸入輸出),例如如下代碼
更多關(guān)于信道(channel)的內(nèi)容,可以前往channel詳解進行了解。
select { case <-ch1: // 如果從 ch1 信道成功接收數(shù)據(jù),則執(zhí)行該分支代碼 case ch2 <- 1: // 如果成功向 ch2 信道成功發(fā)送數(shù)據(jù),則執(zhí)行該分支代碼 default: // 如果上面都沒有成功,則進入 default 分支處理流程 }
語法
Go 編程語言中 select 語句的語法如下:
select { case communication clause : statement(s) case communication clause : statement(s) /* 你可以定義任意數(shù)量的 case */ default : /* 可選 */ statement(s) }
以下描述了 select 語句的語法:
- 每個case都必須是一個通信
- 所有channel表達式都會被求值
- 所有被發(fā)送的表達式都會被求值
- 如果任意某個通信可以進行,它就執(zhí)行;其他被忽略。
- 如果有多個case都可以運行,Select會隨機公平地選出一個執(zhí)行。其他不會執(zhí)行。
否則: - 如果有default子句,則執(zhí)行該語句。
- 如果沒有default字句,select將阻塞,直到某個通信可以運行;Go不會重新對channel或值進行求值。
select的知識點小結(jié)如下:
- select語句只能用于信道的讀寫操作
- select中的case條件(非阻塞)是并發(fā)執(zhí)行的,select會選擇先操作成功的那個case條件去執(zhí)行,如果多個同時返回,則隨機選擇一個執(zhí)行,此時將無法保證執(zhí)行順序。對于阻塞的case語句會直到其中有信道可以操作,如果有多個信道可操作,會隨機選擇其中一個 case 執(zhí)行
- 對于case條件語句中,如果存在信道值為nil的讀寫操作,則該分支將被忽略,可以理解為從select語句中刪除了這個case語句
- 如果有超時條件語句,判斷邏輯為如果在這個時間段內(nèi)一直沒有滿足條件的case,則執(zhí)行這個超時case。如果此段時間內(nèi)出現(xiàn)了可操作的case,則直接執(zhí)行這個case。一般用超時語句代替了default語句
- 對于空的select{},會引起死鎖
- 對于for中的select{}, 也有可能會引起cpu占用過高的問題
實例
package main
import "fmt"
func main() {
var c1, c2, c3 chan int
var i1, i2 int
select {
case i1 = <-c1:
fmt.Printf("received ", i1, " from c1\n")
case c2 <- i2:
fmt.Printf("sent ", i2, " to c2\n")
case i3, ok := (<-c3): // same as: i3, ok := <-c3
if ok {
fmt.Printf("received ", i3, " from c3\n")
} else {
fmt.Printf("c3 is closed\n")
}
default:
fmt.Printf("no communication\n")
}
}
以上代碼執(zhí)行結(jié)果為:
no communication
更多建議: