1、多路选择操作符 select
在golang语言中,select语句 就是用来监听和channel有关的IO操作,当IO操作发生时,触发相应的case动作。有了 select语句,可以实现 main主线程 与 goroutine线程 之间的互动。
select 使用时类似 switch-case 的用法,适用于处理多通道的场景,会通过类似 are-you-ready-polling 的机制来工作。
select {
case <-ch1 : // 检测有没有数据可读
// 一旦成功读取到数据,则进行该case处理语句
case ch2 <- 1 : // 检测有没有数据可写
// 一旦成功向ch2写入数据,则进行该case处理语句
default:
// 如果以上都没有符合条件,那么进入default处理流程
}
2、阻塞与非阻塞 select
select 默认是阻塞的,当没有 case 处于激活状态时,会一直阻塞住,极端的甚至可以这样用:
select {
// 啥也不干,一直阻塞住
}
通过增加 default,可以实现非阻塞的 select
select {
case x, ok := <-ch1:
...
case ch2 <- y:
...
default:
fmt.Println("default")
}
3、多 case 与 default 执行的顺序
整体流程如图所示:
4、注意事项
- 随机性:多个 case 之间并非顺序的,遵循「先到先执行,同时到则随机执行」的原则
- 一次性:和 switch-case 一样,select-case也只会执行一次,如果需要多次处理,需要在外层套一个循环
- default 不会阻塞,会一直执行,当与 for 循环组合使用时可能出现死循环,如下面代码所示:
func main() {
var ch chan int
i := 0
for {
select {
case <-ch: // nil channel 永远阻塞
fmt.Println("never...")
default:
fmt.Printf("in default, i = %d\n", i)
}
i++
}
}