golang中的select机制让我对大师的设计水平赞叹不已,它基于多个阻塞的通道操作(发送或接收),哪个可以执行,就执行哪个。
select {
case <- ch1:
// ...
case x <- ch2:
// use x ...
case ch3 <- y:
// ...
}
前两个case是接收,第三个case是发送。golang的运行机制是,当前的goroutine会阻塞,当ch1或ch2可以接收事件时,或者ch3可以发送事件时,就触发对应的case代码块,然后select块结束。否则将一直阻塞。
select {}
如果不希望select阻塞,则可以设置一个default分支,在所有的case都阻塞地情况下,将会运行default分支。
示例1func fibonacci(c, quit chan int) {
x, y := 0, 1
for {
select {
case c <- x:
x, y = y, x+y
case <-quit:
fmt.Println("quit")
return
}
}
}
func main() {
c := make(chan int)
quit := make(chan int)
go func() {
for i := 0; i < 10; i++ {
fmt.Println(<-c)
}
quit <- 0
}()
fibonacci(c, quit)
}
fibonaccicquit
cfibonacciquitfibonacci
计时器
golang的计时器很适合和select语句搭配使用。
tick := time.Tick(time.Second)
tickchan time.Timetime.Tick()
ticktick
tick.Stop()
select {
case <-time.After(time.Second * 5):
fmt.Println("bingo")
}
time.After
上面的代码将在5秒钟之后打印一句bingo。
计时器+select的示例下面的代码来自《GO程序设计语言》。它实现的功能是,10秒钟之后将会触发一个事件(导弹发射),每秒钟打印一个数字,但是,如果中间用户敲击了一次键盘,则程序终止。
func main() {
abort := make(chan struct{})
go func() {
os.Stdin.Read(make([]byte, 1))
abort <- struct{}{}
}()
tick := time.Tick(time.Second)
for countdown := 10; countdown >= 0; countdown-- {
select {
case <-tick:
fmt.Println(countdown)
case <-abort:
fmt.Println("launch aborted!")
return
}
}
fmt.Println("launch!")
}
time.Tick
time.Sleep(time.Second)