[Golang] Select
文章目录
- [[Golang] Select](#[Golang] Select)
什么是select
select是Golang中一个控制结构,可以用来处理多个channel的发送和接收操作。select会阻塞,直到其中一个case可以执行,然后执行该case。如果有多个case可以执行,则随机执行一个case。
select用法
基本用法
go
package main
func main() {
ch1 := make(chan int,1)
ch2 := make(chan int)
select {
case <-ch1:
// ... 如果ch1读取成功,则执行该case
case ch2<-1:
//... 如果ch2写入成功,则执行该case
default:
//... 如果都不成功,执行default
}
}
select
的用法和switch
比较相似,不过select
的每个case表达式都是channel的读写操作,通过多个case语句
监听多个channel的读写操作是否可以执行;如果没有可以执行的case,就执行default;如果没有default,则当前goroutine会被阻塞。
空select
如果select中什么语句都没有,就会被永久阻塞。
go
package main
func main() {
select {
}
}
执行结果:
golang自带的死锁检测,发现当前goroutine永久不会被唤醒,就会报死锁错误。
没有default且case永久无法执行
go
package main
import "fmt"
func main() {
ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
select {
case <-ch1:
fmt.Println("123")
case <-ch2:
fmt.Println("456")
}
}
执行结果:
两个channel中都没有数据,所以读不出数据,该goroutine会被永久阻塞,
单个case和default
go
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
wg.Add(1)
ch1 := make(chan int, 1)
go func() {
defer wg.Done()
for i := 0; i < 5; i++ {
select {
case <-ch1:
fmt.Println("123")
default:
fmt.Println("default")
}
}
}()
wg.Wait()
}
执行结果:
多个case和default
go
package main
import (
"fmt"
)
func main() {
ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
ch1 <- 1
ch2 <- 2
select {
case <-ch1:
fmt.Println("123")
case <-ch2:
fmt.Println("ABC")
default:
fmt.Println("default")
}
}
执行结果:
有多个case准备好时,会随机执行一个case。
IO多路复用
看到select大家都会联想到Linux中的IO多路复用模型select、poll、epoll,IO多路复用模型是为了提升程序的处理IO时间的性能,其实golang中的select和它们还是有一定区别的。
操作系统的IO多路复用,其实就可以理解为一个或少量线程处理多个IO事件。
传统的阻塞IO:可以理解为一个线程去处理一个IO事件,如果IO事件还没就绪,就阻塞等待。
IO多路复用:一个或少量线程处理多个IO事件。
golang中的select,就是用一个goroutine去监听多个channel的读写事件,提高从多个channel获取信息的效率,也可以理解为一个线程去监控多个IO事件。