select
会 block 到指定的一批 channel ready;如果多个 channel ready,会随机选择其中一个。写法很像 switch
:
select {
// 可以是 receive from channel
case s := <-output:
fmt.Println(s1)
// 也可以是 send to channel
case c <- "hello":
// do nothing
case <-done:
fmt.Println("Done")
}
可以有 default
分支。效果是如果没有 channel ready,就会走 default
:
default:
fmt.Println("None of the other case is ready")
Patterns
select
可以用来表示这一种场景:把一个消息发送到某一 channel;如果无法发送(比如 channel 缓冲区满),则无视。
select {
case c.errors <- err:
default:
// if c.errors is full, do nothing
}
select
经常跟 for
配合,用来实现超时或者退出功能。
实现超时功能(来自 这里):
func main() {
c := boring("Joe")
for {
select {
case s := <-c:
fmt.Println(s)
case <-time.After(1 * time.Second):
fmt.Println("You're too slow.")
return
}
}
}
注意上面的 time.After(1 * time.Second)
是在每次执行 select
语句时都会 evaluate 的,意味着 for 循环中的每次 select
都会有 1s 超时时间。如果你想设置整个 for
循环的超时时间,这样写:
func main() {
c := boring("Joe")
timeout := time.After(5 * time.Second)
for {
select {
case s := <-c:
fmt.Println(s)
case <-timeout:
fmt.Println("You talk too much.")
return
}
}
}
读数据,当读完时执行清理工作(并不实用):
readResult:
for {
select {
case s <- result:
fmt.Println(s)
case <-done:
cleanUp()
break readResult
}
}
因为 break
默认退出的是最内层的 for
/ switch
/ select
语句,因此想 break 掉 for 循环时,需要配合 label(readResult:
)使用。