友情推广
select
在golang中使用select可以实现一个条件选择器,select与switch关键字有着类似的效果,都是实现了一个条件选择器,但是select中的判断条件必须是通信操作,golang中的通信操作是 <- 。当通道在操作符左侧时,表示向通道中写入信息,当通道在操作符右侧时,表示读取通道信息。
// 写入操作
通道 <- 值
// 读取操作
变量 <- 通道
编写select条件选择器的语法格式是:
select {
case <- ch1:
// 读取通道ch1,读取成功,执行这个分支。
// do something
case val := <- ch2:
// 读取通道ch2,读取成功,执行这个分支。
// do something
case ch3 ->:
// 想
// do something
default:
// do something
}
在golang中,支持通信操作的类型只有chan,所以select中的case条件只能是对chan类型变量的读写操作。由于chan类型变量的读写操作可能会引起阻塞,为了在使用select选择器时不陷入阻塞状态,可以在select代码块中添加default关键字,当case条件全部都不满足时,默认进入default分支,执行完default分支的代码后,退出select选择器。
下边来一个例子来使用select实现条件选择。
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("开始时间:", time.Now().Format("2006-01-02 15:04:05"))
select {
case <-time.After(time.Second * 2):
fmt.Println("2秒后的时间:", time.Now().Format("2006-01-02 15:04:05"))
}
}
输出信息是:
开始时间: 2017-09-15 23:23:10
2秒后的时间: 2017-09-15 23:23:12
time.After函数返回一个通道类型的变量,然后在case中从这个通道中读取信息,如果没有协程给这个通道发送信息,那么case将会一直阻塞。在调用After函数时,传入了一个时长作为参数,意思是从调用After函数算起,到设定的市场后,有协程将会向这个通道发送一条消息。当通道收到消息后,这个case条件满足,这个case分支下的代码将会被执行。
当select中同一时间,有多个case满足条件时,select会选择哪一个分支执行,还是执行多个分支呢?答案是:随机选择一个满足满足条件的case分支执行,这个分支执行完成后,退出select选择器。请记住:是随机选择一个满足条件的case分支执行。下边请看示例:
package main
import (
"fmt"
"time"
)
func main() {
var ch1 chan int = make(chan int)
var ch2 chan int = make(chan int)
go func() {
fmt.Println("从通道ch2中读取数据:", <-ch2)
}()
go func() {
ch1 <- 88
}()
select {
case <-time.After(time.Second * 5):
// do something
fmt.Println("timeout")
case val := <-ch1:
fmt.Println("从通道ch1中读取数据", val)
// do something
case ch2 <- 99:
// do something
}
time.Sleep(time.Second * 2)
}
输出信息有两种情况,一种是:
从通道ch2中读取数据: 99
另一种是:
从通道ch1中读取数据 88