Go里面的一个关键字,用于监听channel上的数据流动。select语句里面的每条case语句必须是一个IO操作。
select {
case <- chan1;
//如果chan1成功读 取到数据,则进行该case语句处理。
case chan2 <- 1;
//如果成功向chan2中写入数据,则进行case语句处理。
default;
//如果上面都没有成功,则进入default语句处理,通常不用(会产生忙轮训)
}
代码示例:
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)//关闭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
###############
斐波那契数列:
package main
import (
"fmt"
"runtime"
)
//打印输出Fibonacci
func fibonacci (ch <- chan int,quit <- chan bool) {
for {
select {
case num := <- ch://从管道中读取数据
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、监听的case中,没有满足的监听条件,阻塞。
2、监听的case中,有多个满足监听条件,任选一个执行。
3、可以使用default来处理所有的case都不满足的条件的状况,通常不用(会产生忙轮训)。
4、select自身不带有循环机制,需要借助外层的for循环来监听。
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: //这里阻塞了,因为没有写
fmt.Println("num=",num)
//case <- timer.C: //等待3秒后,把系统时间读取出来
case <- time.After(3*time.Second)://等待3秒后,把系统时间读取出来
fmt.Println("超时")
quit <- true//判断是否退出
break
}
}
}()
<- quit//主goroutine从管道中读取
}