e v1 := <-ch1:
...
// ch2有数据时,读取到v2变量中
case v2 := <-ch2:
...
// 所有case都不满足条件时,执行default
default:
...
}
defalut语句是可选的,不允许fall through行为,但允许case语句块为空块。select会被return、break关键字中断。
select的行为模式主要是对channel是否可读进行轮询,但也可以用来向channel发送数据。它的行为如下:
- 如果所有的case语句块都被阻塞,则阻塞直到某个语句块可以被处理
- 如果多个case同时满足条件,则随机选择一个进行处理
- 如果存在default且其它case都不满足条件,则执行default。所以default必须要可执行而不能阻塞
需要注意的是,如果在select中执行send操作,则可能会永远被send阻塞。所以,在使用send的时候,应该也使用defalut语句块,保证send不会被阻塞。
一般来说,select会放在一个无限循环语句中,一直轮询channel的可读事件。
下面是一个示例,pump1()和pump2()都用于产生数据(一个产生偶数,一个产生奇数),并将数据分别放进ch1和ch2两个通道,suck()则从ch1和ch2中读取数据。然后在无限循环中使用select轮询这两个通道是否可读,最后main goroutine在1秒后强制中断所有goroutine。
package main
import (
"fmt"
"time"
)
func main() {
ch1 := make(chan int)
ch2 := make(chan int)
go pump1(ch1)
go pump2(ch2)
go suck(ch1, ch2)
time.Sleep(1e9)
}
func pump1(ch chan int) {
for i := 0; i <= 30; i++ {
if i%2 == 0 {
ch <- i
}
}
}
func pump2(ch chan int) {
for i := 0; i <= 30; i++ {
if i%2 == 1 {
ch <- i
}
}
}
func suck(ch1 chan int, ch2 chan int) {
for {
select {
case v := <-ch1:
fmt.Printf("Recv on ch1: %d\n", v)
case v := <-ch2:
fmt.Printf("Recv on ch2: %d\n", v)
}
}
}