- 每個 case 都必須是一個通信(IO 操作)
- 所有 channel 表達式都會被求值(所有被發送的表達式都會被求值)
- 如果任意某個通信可以進行,它就執行,其他被忽略。
-
如果有多個 case 都可以運行,Select 會隨機公平地選出一個執行。其他不會執行
。
【示例一 實際測試不是隨機的 因為不帶緩沖區的channel是阻塞的】 - 如果有 default 子句,則執行該語句。
- 如果沒有 default 子句,select 將阻塞,直到某個通信可以運行;Go 不會重新對 channel 或值進行求值。
示例一
【示例一 實際測試不是隨機的?因為不帶緩沖區的channel是阻塞的】
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
ch3 := make(chan int)
quit := make(chan bool)
//新開一個協程
go func() {
for {
time.Sleep(1 * time.Second)
select {
case num := <-ch1:
fmt.Println("num1 = ", num)
case num := <-ch2:
fmt.Println("num2 = ", num)
case num := <-ch3:
fmt.Println("num3 = ", num)
case <-time.After(3 * time.Second):
fmt.Println("超時")
quit <- true
}
}
}() //別忘了()
for i := 0; i < 6; i++ {
ch1 <- i
ch3 <- i
ch2 <- i
//time.Sleep(time.Second)
}
<-quit
fmt.Println("程序結束")
}
- 執行順序【隨機】
select 不會按照任何規則或者優先級選擇到達的channel。go標準庫在每次訪問的時候,都會將他們順序打亂,也就是說不能保證任何順序
https://segmentfault.com/a/1190000022520711
package main
func main() {
a := make(chan bool, 100)
b := make(chan bool, 100)
c := make(chan bool, 100)
for i := 0; i < 10; i++ {
a <- true
b <- true
c <- true
}
for i := 0; i < 10; i++ {
select {
case <-a:
print("< a")
case <-b:
print("< b")
case <-c:
print("< c")
default:
print("< default")
}
}
}
//程序的輸出 < b< a< a< b< c< c< c< a< b< b
由于go 不會刪除重復的channel,所以可以使用多次添加case來影響結果
func main() {
a := make(chan bool, 100)
b := make(chan bool, 100)
c := make(chan bool, 100)
for i := 0; i < 10; i++ {
a <- true
b <- true
c <- true
}
for i := 0; i < 10; i++ {
select {
case <-a:
print("< a")
case <-a:
print("< a")
case <-a:
print("< a")
case <-a:
print("< a")
case <-a:
print("< a")
case <-a:
print("< a")
case <-a:
print("< a")
case <-b:
print("< b")
case <-c:
print("< c")
default:
print("< default")
}
}
}
輸出的結果:
< c< a< b< a< b< a< a< c< a< a