Go语言-select 语句

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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`语句是并发控制的关键组成部分,主要用于处理多个通信信道(channels)上的消息。它允许goroutines(协程)同时监听多个通道并根据可用的消息执行相应的分支。当`select`遇到活跃的通道时,它会选择该通道上可读的数据进行操作,否则会阻塞等待。 `select`的基本语法结构如下: ```go select { case channel1 <- value1: // 当channel1有数据可写时执行此分支 case channel2 <- value2: // 当channel2有数据可写时执行此分支 ... default: // 没有活跃通道时执行此默认分支 } ``` 这里,`case`后的`channel <- value`表示发送值到通道,如果通道已经关闭(`close(channel)`),则对应的分支会被跳过;如果没有活跃的通道,则执行`default`分支(如果有定义的话)。 `select`的应用场景包括: 1. **网络编程**:用于从多个网络套接字或连接中接收数据,或者往这些通道发送数据。 2. **异步事件驱动**:例如处理来自文件描述符、定时器、TCP连接等的I/O事件。 3. **消息传递**:在多线程或多进程间的通信中,goroutines可以通过select轮流检查多个通道是否有新的消息。 4. **信号处理**:在等待特定信号(如键盘中断或定时器到期)时使用select。 一个典型的例子可能是从多个channel中选择最早触发的消息处理: ```go package main import ( "fmt" "time" ) func main() { messageChs := make([]chan string, 3) for i := 0; i < len(messageChs); i++ { messageChs[i] = make(chan string) } var wg sync.WaitGroup wg.Add(2) go func() { defer wg.Done() time.Sleep(time.Second) // 模拟第一个消息延迟 messageChs[0] <- "Message from channel 1" }() go func() { defer wg.Done() messageChs[1] <- "Message from channel 2" }() select { case msg := <-messageChs[0]: fmt.Println("Received:", msg) case msg := <-messageChs[1]: fmt.Println("Received:", msg) default: fmt.Println("No message available") } wg.Wait() } ``` 在这个例子中,`select`会根据哪个通道先发送消息来打印结果,从而实现了并发处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

西京刀客

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

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

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

打赏作者

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

抵扣说明:

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

余额充值