golang中的select机制让我对大师的设计水平赞叹不已,它基于多个阻塞的通道操作(发送或接收),哪个可以执行,就执行哪个。
select {
case <- ch1:
// ...
case x <- ch2:
// use x ...
case ch3 <- y:
// ...
}
前两个case是接收,第三个case是发送。golang的运行机制是,当前的goroutine会阻塞,当ch1或ch2可以接收事件时,或者ch3可以发送事件时,就触发对应的case代码块,然后select块结束。否则将一直阻塞。
一个空的select {}
将使当前的goroutine永久阻塞。
如果不希望select阻塞,则可以设置一个default分支,在所有的case都阻塞地情况下,将会运行default分支。
这个示例来自官网的demo https://tour.golang.org/concurrency/5
func 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)
}
在fibonacci
函数中,一个死循环中包含一个select,也就是意味着,每次当c
通道的事件被接收一次,此时通道就允许发送一个新事件,对应的case代码块就运行一次,直到quit
有了新的事件,此时退出死循环。
在main函数中启动了一个独立的goroutine来运行匿名函数,这个匿名函数接收10次c
通道的事件,导致fibonacci
函数的第一个case条件触发了10次,然后,匿名函数向quit
通道发送了一个事件,从而结束掉fibonacci
的死循环,此时main函数也结束了。
golang的计时器很适合和select语句搭配使用。
tick := time.Tick(time.Second)
上面代码中的 tick
是一个chan time.Time
类型的通道,这个通道中会每秒产生一个事件,事件的内容是当前时间。时间间隔是由time.Tick()
的参数指定的。
tick
通道没有缓冲,这意味着如果tick
通道中的事件被接收了,那么1秒之后还会再产生一个新的事件,但如果不接收的话,新的事件无法被发送到通道中。
通过tick.Stop()
来停止计时器,否则可能造成goroutine泄露。
select {
case <-time.After(time.Second * 5):
fmt.Println("bingo")
}
上面的time.After
,返回一个通道,这个通道在指定的时间间隔之后将会产生一个事件。
上面的代码将在5秒钟之后打印一句bingo。
下面的代码来自《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!")
}
这就是一个典型的循环+select的代码结构,循环中的select监听两个通道,第一个通道来自time.Tick
,每秒钟产生一个事件,有一次的运行机会,另一个通道来自用户输入。当循环结束时,将会执行最后一行代码,当用户取消时,直接退出main函数。
在循环中select一个tick通道,每秒钟最多循环一次,就像具备time.Sleep(time.Second)
的效果一样。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://blog.csdn.net/daguanjia11/article/details/121324055
内容来源于网络,如有侵权,请联系作者删除!