select
select 是 go 语言中的一种条件控制语句,类似于之前学习的 switch 条件控制语句,不同的是 select 只能用于通道的控制,在 select 中同样可以有多个 case 分支和一个 default 分支,但是每一个 case 必须都是 channel 的操作,可以是发送也可以是接收,select 会一直等待,直到某一个 case 分支的 channel 操作完成之后就执行对应的代码语句。
基本语法:
select {
case channel 语句 1 :
// 匹配到 channel 语句 1 则执行该内容
case channel 语句 2 :
// 匹配到 channel 语句 1 则执行该内容
default : // 默认执行
// default 内容
}
select 同时监听多个分支,一直堵塞直到其中一个分支完成 channel
代码示例:
package main
import (
"fmt"
)
func main() {
intChan := make(chan int)
stringChan := make(chan string)
go func(ch chan int) {
time.Sleep(time.Second * 2)
ch <- 1
}(intChan)
go func(ch chan string) {
time.Sleep(time.Second)
ch <- "a"
}(stringChan)
select {
case i := <- intChan: // 监听 intChan 的操作
fmt.Println(i)
case s := <- stringChan: // 监听 stringChan 的操作
fmt.Println(s)
}
}
上述代码中的 select 有两个 case 分支,分别监听了 intChan 和 stringChan 两个通道,然后在程序中启动两个 goroutine 分别对这两个通道发送数据,则 select 会一直堵塞,直到其中一个 case 的 channel 接收到数据就执行其对应的输出语句,由于在往 intChan 中发送数据之前有两秒钟的睡眠时间, stringChan 只有一秒钟的睡眠时间,所以当前代码中永远都是 stringChan 先好,最后的结果则是在控制台打印字母 a。
在 select 中增加 default 语句后则不会一直堵塞等待
代码示例:
select {
case i := <- intChan:
fmt.Println(i)
case s := <-stringChan:
fmt.Println(s)
default:
fmt.Println("default操作")
}
在保持上面代码都不变的情况下,仅在 select 语句的最后加入一个 default 分支,这样再次运行代码就会打印输出 default操作
,这是因为在 select 语句中加入 default 之后就不会堵塞等待,而且在 intChan 和 stringChan 中分别有一秒和两秒的沉睡,当执行到 select 语句时,两个 channel 都没有准备好,就会直接执行 default 分支的内容。
当多个 channel 同时准备好时,随机执行其中一个
代码示例:
package main
import (
"fmt"
"time"
)
func main() {
intChan := make(chan int)
stringChan := make(chan string)
go func(ch chan int) {
ch <- 1
}(intChan)
go func(ch chan string) {
ch <- "a"
}(stringChan)
time.Sleep(time.Second) // 睡眠一秒钟,确保两个 channel 都准备好
select {
case i := <- intChan:
fmt.Println(i)
case s := <-stringChan:
fmt.Println(s)
}
}
上面的代码中,在 select 语句之前睡眠了一秒钟,用于确保前面两个 goroutine 都执行完毕并把数据发送到 channel 中,然后再执行后面的 select 语句,这时候执行到 select 语句时,intChan 和 stringChan 都是准备就绪状态,则这时候 select 会随机选择一个 case 分支执行,所以在最后的输出结果中会随机在控制台打印数字 1 或者字母 a。
select 总结:
-
每一个 case 都必须是一个通道操作。 -
没有 default 分支时,select 会堵塞,有 default 分支时直接执行 default 分支内容。 -
如果有多个 case 分支同时准备就绪,则随机执行其中一个,其他的则忽略。
原文始发于微信公众号(良猿):Java转Go—16Select
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/215796.html