select完成对多个channel监控
假如现在有两个方法,分别有对应的channel,每当他们运行完成之后会向channel中发送一个信号。现在想要知道是哪一个方法先完成,可以如何做?
此时可以使用select方法,来对channel进行监控。
select的语法和switch很像,例如:
func g1(ch chan struct{}) {
time.Sleep(time.Second)
ch <- struct{}{}
}
func g2(ch chan struct{}) {
time.Sleep(2*time.Second)
ch <- struct{}{}
}
func main() {
ch1 := make(chan struct{})
ch2 := make(chan struct{})
go g1(ch1)
go g2(ch2)
select {
case <-ch1:
fmt.Println("g1 done")
case <-ch2:
fmt.Println("g2 done")
}
}
运行结果为:
g1 done
假如我现在将这个select放到一个for循环中,不断地监控两个channel,并且想要当超过一定的时间之后就自动退出,也就是设定超时时间,这个时候可以使用 time.NewTimer()
这个方法接收一个时间做为参数,并返回一个timer对象,这个对象有一个成员 C
是一个channel,当时间到达时timer会往这个timer中发送一个信号。我们可以根据这个原理来完成超时时间的设置比如:
func g1(ch chan struct{}) {
time.Sleep(time.Second)
ch <- struct{}{}
}
func g2(ch chan struct{}) {
time.Sleep(2*time.Second)
ch <- struct{}{}
}
func main() {
ch1 := make(chan struct{})
ch2 := make(chan struct{})
timer := time.NewTimer(4*time.Second)
go g1(ch1)
go g2(ch2)
for {
select {
case <-ch1:
fmt.Println("g1 done")
case <-ch2:
fmt.Println("g2 done")
case <-timer.C:
fmt.Println("time out!")
return
}
}
}
运行结果如下:
g1 done
g2 done
time out!
同时和switch一样,select也支持default方法,当没有读取到值时就运行default。
关于select还有两点需要注意的:
- select时某一个分支就绪了(获取到了值)就执行哪一个分支
- 如果多个分支同时就绪,是随机执行,目的是为了防止一直读取某一个分支的值,从而造成”饥饿“现象