为了应对同时从多个通道接收数据,Go内置了
select关键字
1. select的作用
select类似switch,它有一系列的分支和默认分支,每一个case必须是一个通道的通信过程(接收或发送)。执行select后一直阻塞,直到其中一个case的通信操作完成时,它会执行case分支的对应语句,执行完后退出select。
例子:
ch1 := make(chan int, 1)ch2 := make(chan int, 1)ch1 <- 1ch2 <- 2select {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 <- 1ch2 <- 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 := igo func(index int) {ch <- index}(index)}count := 0EXIT:for {select {case index := <-ch:fmt.Println(index)count++if count == 5 {// 通过break标签退出for循环break EXIT}}}fmt.Println("end...")wg.Done()}
