golang 中的 select 就是用来监听和 channel 有关的 IO 操作,当 IO 操作发生时,触发相应的动作。select 只能应用于 channel 的操作,既可以用于 channel 的数据接收,也可以用于 channel 的数据发送。如果 select 的多个分支都满足条件,则会随机的选取其中一个满足条件的分支执行。
1,Golang select基本用法
语法
select {
case <- chan1:
// 如果 chan1 成功读到数据,则进行该 case 处理语句
case chan2 <- 1:
// 如果成功向 chan2 写入数据,则进行该 case 处理语句
default:
// 如果上面都没有成功,则进入default处理流程
}
说明
select 里面即可以对 channel 进行读取,还可以对 channel 进行写入,如果所有条件都不满足,并且有 default 子句,则执行 default 子句,否则,会阻塞。
Golang select典型用法
阻塞
所有条件都不满足,则永久阻塞
package main import ( "fmt" ) func main() {
fmt.Println("嗨客网(www.haicoder.net)")
ch := make(chan int, 1)
select { case <-ch:fmt.Println("Received from ch") }
}
程序运行后,输出如下图所示:

我们看到,此时,程序死锁了,因为 select 中永远不可能有满足的条件,即,select 会永久阻塞。
执行默认分支
如果有 default 分支,并且所有条件都不满足,则执行 default 分支
package main import ( "fmt" )
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
ch := make(chan int, 1)
select {
case <-ch: fmt.Println("Received from ch")
default:
fmt.Println("Run in default")
}
}
程序运行后,输出如下图所示:

我们看到,此时,select 中的所有条件都不满足,因此,执行了 default 字句。
执行分支
如果有满足的分支,则执行对应的分支
package main import ( "fmt" )
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
ch := make(chan int, 1)
ch <- 1024
select {
case val := <-ch:
fmt.Println("Received from ch, val =", val)
default:
fmt.Println("Run in default")
}
}
程序运行后,输出如下图所示:

我们看到,此时,select 中的第一个分支与 default 分支同时都满足,执行了第一个分支。
多个分支同时满足
如果多个分支同时满足,则随机选择执行
package main import ( "fmt" )
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
ch := make(chan int, 1)
ch <- 1024
select {
case val := <-ch:
fmt.Println("Received from ch1, val =", val)
case val := <-ch:
fmt.Println("Received from ch2, val =", val)
case val := <-ch:
fmt.Println("Received from ch3, val =", val)
default:
fmt.Println("Run in default")
}
}
程序运行后,输出如下图所示:

我们多运行几次,发现,第一个 case、第二个 case 和第三个 case 都会被执行,即,此时所有条件都满足,则随机选择一个 case 执行。
超时机制
select 可以用于控制超时
package main import ( "fmt" "time" )
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
timeout := make(chan bool, 1)
ch := make(chan int)
go func() {
time.Sleep(2 * time.Second)
timeout <- true }()
select {
case <-ch:
fmt.Println("received from ch")
case <-timeout:
fmt.Println("select timeout")
}
}
程序运行后,输出如下图所示:

这里,我们使用了 sleep 模拟了超时。
select time.After
select 可以用 time.After 控制超时
package main import ( "fmt" "time" )
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
ch := make(chan int)
select {
case <-ch:
fmt.Println("received from ch")
case <-time.After(time.Second * 2):
fmt.Println("select timer after timeout")
}
}
程序运行后,输出如下图所示:

这里,我们使用了 time.After 实现了超时控制。
select和for循环使用
可以在 for 循环里面使用 select
package main import ( "fmt" "time" )
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
c1 := make(chan string)
c2 := make(chan string)
go func() {
time.Sleep(time.Second * 1)
c1 <- "one" }()
go func() {
time.Sleep(time.Second * 2)
c2 <- "two" }()
for i := 0; i < 2; i++ {
select {
case msg1 := <-c1:
fmt.Println("received", msg1)
case msg2 := <-c2:
fmt.Println("received", msg2)
}
}
}
程序运行后,输出如下图所示:

我们在 for 循环里面使用了 select。
Golang select使用总结
golang 中的 select 就是用来监听和 channel 有关的 IO 操作,当 IO 操作发生时,触发相应的动作。
select 只能应用于 channel 的操作,既可以用于 channel 的数据接收,也可以用于 channel 的数据发送。如果 select 的多个分支都满足条件,则会随机的选取其中一个满足条件的分支执行。
2190

被折叠的 条评论
为什么被折叠?



