select
作用:
可以监听多个通道(同switch-case语句基本一样)
select的一大限制: 每一个case语句中必须是一个IO操作
select {
case <- chan1:
//如果chan1成功读取到该数据,就进行该case处理语句
case chan2 <- 1:
//如果chan2成功写入数据,就进行该case处理语句
default:
//如果上面都没有成功,则进入default处理流程
}
如果没有任意一个条语句可以执行(即所有的通道都被阻塞),会出现两种情况:
- 如果有default语句,那么就执行default语句,同时程序的执行会从select语句后的语句中恢复.
- 没有default语句,那么select语句将被阻塞,直到至少有一个通信可以进行下去.
注意: 一般不使用default语句,如果其它case不满足条件会阻塞,最后会执行到default(不会阻塞),程序会不停地轮询
场景:如果监听到数据通道有值就打印,如果监听到退出开关有值就退出
func main() {
c:=make(chan int) //数据通道
quit:=make(chan bool) //退出开关
//子go程写数据
go func() {
for i:=1;i<=5 ;i++ {
c<-i //将i写入通道
time.Sleep(time.Second)
}
quit<-true //退出开关
}()
//主go程读数据
for {
select{ //用来监听通道
case num:=<-c:
fmt.Println("读取到",num)
case <-quit:
return ;
}
time.Sleep(time.Second)
}
}
- select只是监听通道,不会阻塞(case可以产生阻塞)
- 在select中不用设置default,防止忙轮训在select中不用设置default,防止忙轮询
select实现超时退出
场景:有时候会出现go程阻塞的情况,可以利用select来设置超时,避免整个程序进入阻塞
func main() {
c:=make(chan int)
quit:=make(chan bool)
go func() {
for {
select{
case num:=<-c:
fmt.Println(num)
case <-time.After(time.Second*2):
fmt.Println("超时退出")
quit<-true
}
}
}()
<-quit
}
空的select可以阻塞 main 函数
func main() {
go func() {
for{
fmt.Println("Golang")
}
}()
select { //阻塞
}
}
此处的select{}会阻塞main函数,让其不退出,一直在后台执行(相当于for{}死循环)。