Go里面的一個關(guān)鍵字,用于監(jiān)聽channel上的數(shù)據(jù)流動。select語句里面的每條case語句必須是一個IO操作。
select {
case <- chan1;
//如果chan1成功讀 取到數(shù)據(jù),則進(jìn)行該case語句處理。
case chan2 <- 1;
//如果成功向chan2中寫入數(shù)據(jù),則進(jìn)行case語句處理。
default;
//如果上面都沒有成功,則進(jìn)入default語句處理,通常不用(會產(chǎn)生忙輪訓(xùn))
}
代碼示例:
package main
import (
"fmt"
"runtime"
"time"
)
func main () {
//定義兩個channel
ch := make(chan int)//用于通信
quit := make(chan bool)//用于判斷是否退出
//新建一個子goroutine,用于channel寫
go func() {
for i :=0; i < 5; i++ {
ch <- i
time.Sleep(time.Second)
}
close(ch)//關(guān)閉channel
quit <- true//通知主goroutine是否退出
runtime.Goexit()
}()
//主goroutine用于讀取
for {
select {
case num := <- ch :
fmt.Println("讀到:",num)
case <- quit:
return
}
fmt.Println("###############")
}
}
輸出:
讀到: 0
###############
讀到: 1
###############
讀到: 2
###############
讀到: 3
###############
讀到: 4
###############
斐波那契數(shù)列:
package main
import (
"fmt"
"runtime"
)
//打印輸出Fibonacci
func fibonacci (ch <- chan int,quit <- chan bool) {
for {
select {
case num := <- ch://從管道中讀取數(shù)據(jù)
fmt.Print(num," ")
case <- quit:
runtime.Goexit()//退出子goroutine
}
}
}
func main () {
//定義兩個channel
ch := make(chan int)//用于通信
quit := make(chan bool)//用于判斷主goroutine是否退出
go fibonacci(ch,quit)//打印輸出Fibonacci
//主goroutine用于計算
x,y := 1,1
for i := 0; i < 20; i++ {
ch <- x
x, y = y, x + y
}
quit <- true
}
注意事項:
1、監(jiān)聽的case中,沒有滿足的監(jiān)聽條件,阻塞。
2、監(jiān)聽的case中,有多個滿足監(jiān)聽條件,任選一個執(zhí)行。
3、可以使用default來處理所有的case都不滿足的條件的狀況,通常不用(會產(chǎn)生忙輪訓(xùn))。
4、select自身不帶有循環(huán)機(jī)制,需要借助外層的for循環(huán)來監(jiān)聽。
5、break只能跳出select,類似于switch中的用法。不能使用break跳出主goroutine,如果要跳 出子goroutine,可以使用runtime.Goexit()
超時:
package main
import (
"fmt"
"time"
)
func main () {
ch := make(chan int)
quit := make(chan bool)
//timer := time.NewTimer(time.Second*3)
go func() {
for {
select {
case num := <- ch: //這里阻塞了,因?yàn)闆]有寫
fmt.Println("num=",num)
//case <- timer.C: //等待3秒后,把系統(tǒng)時間讀取出來
case <- time.After(3*time.Second)://等待3秒后,把系統(tǒng)時間讀取出來
fmt.Println("超時")
quit <- true//判斷是否退出
break
}
}
}()
<- quit//主goroutine從管道中讀取
}