Go语言-select 语句

本文深入解析Go语言中的select语句,介绍其基本用法、如何实现timeout机制、检测channel是否已满,以及default分支的作用。select语句在Go中用于监听channel上的数据流动,与switch语句类似但专门用于IO操作。

Go 语言 select 语句

go select 用法
参考URL: https://www.jianshu.com/p/a69e896e261a

Go里面提供了一个关键字select,通过select可以监听channel上的数据流动。

select的用法与switch语言非常类似,由select开始一个新的选择块,每个选择条件由case语句来描述。
与switch语句相比, select有比较多的限制,其中最大的一条限制就是每个case语句里必须是一个IO操作。

总结: golang 的 select 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。 golang 的 select 的功能和 select, poll, epoll 相似, 就是监听 IO 操作,当 IO 操作发生时,触发相应的动作。

select知识点

  • select语句只能用于信道的读写操作
  • select中的case条件(非阻塞)是并发执行的,select会选择先操作成功的那个case条件去执行,如果多个同时返回,则随机选择一个执行,此时将无法保证执行顺序。对于阻塞的case语句会直到其中有信道可以操作,如果有多个信道可操作,会随机选择其中一个 case 执行。

使用 select 实现 timeout 机制

timeout := make (chan bool, 1)
go func() {
    time.Sleep(1e9) // sleep one second
    timeout <- true
}()
ch := make (chan int)
select {
case <- ch:
case <- timeout:
    fmt.Println("timeout!")
}

当超时时间到的时候,case2 会操作成功。 所以 select 语句则会退出。 而不是一直阻塞在 ch 的读取操作上。 从而实现了对 ch 读取操作的超时设置

使用 select 语句来检测 chan 是否已经满了

当 select 语句带有 default 的时候

ch1 := make (chan int, 1)
ch2 := make (chan int, 1)

select {
case <-ch1:
    fmt.Println("ch1 pop one element")
case <-ch2:
    fmt.Println("ch2 pop one element")
default:
    fmt.Println("default")
}

此时因为 ch1 和 ch2 都为空,所以 case1 和 case2 都不会读取成功。 则 select 执行 default 语句。
就是因为这个 default 特性, 我们可以使用 select 语句来检测 chan 是否已经满了。

ch := make (chan int, 1)
ch <- 1
select {
case ch <- 2:
default:
    fmt.Println("channel is full !")
}

因为 ch 插入 1 的时候已经满了, 当 ch 要插入 2 的时候,发现 ch 已经满了(case1 阻塞住), 则 select 执行 default 语句。 这样就可以实现对 channel 是否已满的检测, 而不是一直等待。

比如我们有一个服务, 当请求进来的时候我们会生成一个 job 扔进 channel, 由其他协程从 channel 中获取 job 去执行。 但是我们希望当 channel 满了的时候, 将该 job 抛弃并回复 【服务繁忙,请稍微再试。】 就可以用 select 实现该需求。

select 语句default 分支

golang中的select语句格式如下

select {
    case <-ch1:
        // 如果从 ch1 信道成功接收数据,则执行该分支代码
    case ch2 <- 1:
        // 如果成功向 ch2 信道成功发送数据,则执行该分支代码
    default:
        // 如果上面都没有成功,则进入 default 分支处理流程
}

**如果 ch1 或者 ch2 信道都阻塞的话,就会立即进入 default 分支,并不会阻塞。**但是如果没有 default 语句,则会阻塞直到某个信道操作成功为止。

参考

go select的用法
参考URL: https://www.cnblogs.com/gwyy/p/13629999.html

### 使用方法 Go 编程语言select 语句的语法如下: ```go select { case communication clause : statement(s) case communication clause : statement(s) /* 可以定义任意数量的 case */ default : /* 可选 */ statement(s) } ``` 在这个语法结构中,`case` 后面跟的是通信操作,如 `channel` 的发送或接收操作。当 `select` 语句执行时,会检查每个 `case` 语句中的通信操作是否可以执行,如果有多个 `case` 都可以执行,会随机选择一个执行;如果没有可执行的 `case`,且有 `default` 分支,则执行 `default` 分支的语句;如果没有 `default` 分支,`select` 语句会阻塞,直到有一个 `case` 可以执行 [^3]。 ### 应用场景 - **实现 timeout 机制**:在需要等待 `channel` 操作,但又不想无限期等待的场景下,可以使用 `select` 结合 `time.After` 实现超时机制。示例代码如下: ```go package main import ( "fmt" "time" ) func main() { ch := make(chan int) go func() { time.Sleep(2 * time.Second) ch <- 1 }() select { case val := <-ch: fmt.Println("Received:", val) case <-time.After(1 * time.Second): fmt.Println("Timeout!") } } ``` - **检测 `chan` 是否已经满了**:通过 `select` 语句和 `default` 分支可以检测 `channel` 是否已满。示例代码如下: ```go package main import "fmt" func main() { ch := make(chan int, 1) ch <- 1 select { case ch <- 2: fmt.Println("Channel is not full, sent 2") default: fmt.Println("Channel is full") } } ``` - **协调多个 `channel` 的读写操作**:`select` 可以协调多个 `channel` 的读写操作,使得能够在多个 `channel` 中进行非阻塞的数据传输、同步和控制 [^4]。 ### 注意事项 - **随机性**:当多个 `case` 都可以执行时,`select` 会随机选择一个执行,这可能会导致程序的行为具有一定的不确定性。 - **阻塞问题**:如果没有 `default` 分支,且所有 `case` 都不能执行,`select` 语句会阻塞,可能会导致程序出现死锁。 - **资源管理**:在使用 `select` 处理 `channel` 时,要注意 `channel` 的关闭和资源释放,避免出现资源泄漏。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

西京刀客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值