为了应对同时从多个通道接收数据,Go内置了
select
关键字
1. select的作用
select
类似switch
,它有一系列的分支和默认分支,每一个case必须是一个通道的通信过程(接收或发送)。执行select
后一直阻塞,直到其中一个case的通信操作完成时,它会执行case分支的对应语句,执行完后退出select。
例子:
ch1 := make(chan int, 1)
ch2 := make(chan int, 1)
ch1 <- 1
ch2 <- 2
select {
case s := <-ch1:
fmt.Println(s)
case s := <-ch2:
fmt.Println(s)
}
2. case的执行顺序
看了上面的例子,可能会想select
的case是按顺序执行的?先不着急下结论,再写个例子执行看看
例子:
ch1 := make(chan int, 11)
ch2 := make(chan int, 11)
for i := 0; i < 10; i++ {
ch1 <- 1
ch2 <- 2
}
for i := 0; i < 10; i++ {
select {
case s := <-ch1:
fmt.Println(s)
case s := <-ch2:
fmt.Println(s)
}
}
打印输出:
嗯,不是我们想象的1、2轮流打印。得出的结论:当同时有多个case的通道通信操作完成时,select
的case不是顺序执行的,而是随机选择一个执行。
3. for select
大多时候我们会使用for结合select使用,需要注意一下如何退出for循环
func main() {
wg := &sync.WaitGroup{}
wg.Add(1)
test(wg)
wg.Wait()
}
func test(wg *sync.WaitGroup) {
ch := make(chan int)
for i := 1; i < 6; i++ {
index := i
go func(index int) {
ch <- index
}(index)
}
count := 0
EXIT:
for {
select {
case index := <-ch:
fmt.Println(index)
count++
if count == 5 {
// 通过break标签退出for循环
break EXIT
}
}
}
fmt.Println("end...")
wg.Done()
}