目录
- 关键点:
- 示例代码
- 代码说明:
- 可能的输出:
- 总结:
在 Go 的 select
语句中,如果多个 case
同时满足条件,Go 会随机选择一个执行,而其他满足条件的 case
不会被执行。也就是说,select
语句只会执行一个 case
,其余的 case
会被忽略。
关键点:
-
select
的执行机制:select
会检查所有case
的条件。- 如果有多个
case
满足条件(例如多个 channel 同时有数据可读或可写),Go 会随机选择一个case
执行。 - 其他满足条件的
case
不会被执行,也不会被“保存”到下一次select
。
-
未执行的
case
:- 如果一个
case
在本次select
中没有被选中执行,那么它的状态会被保留。 - 如果这个
case
的条件仍然满足(例如 channel 中仍有数据),它可以在下一次select
中被选中执行。
- 如果一个
示例代码
以下是一个示例,展示了多个 case
同时满足条件时,select
的行为:
package mainimport ("fmt""time"
)func main() {ch1 := make(chan string)ch2 := make(chan string)// 启动一个 goroutine 向 ch1 发送数据go func() {time.Sleep(100 * time.Millisecond)ch1 <- "message from ch1"}()// 启动一个 goroutine 向 ch2 发送数据go func() {time.Sleep(100 * time.Millisecond)ch2 <- "message from ch2"}()// 使用 select 监听多个 channelselect {case msg := <-ch1:fmt.Println("Received from ch1:", msg)case msg := <-ch2:fmt.Println("Received from ch2:", msg)default:fmt.Println("No message received")}// 再次使用 select 监听select {case msg := <-ch1:fmt.Println("Received from ch1:", msg)case msg := <-ch2:fmt.Println("Received from ch2:", msg)default:fmt.Println("No message received")}
}
代码说明:
- 创建了两个 channel
ch1
和ch2
。 - 启动两个 goroutine,分别向
ch1
和ch2
发送数据,发送操作有 100 毫秒的延迟。 - 使用
select
监听ch1
和ch2
。- 由于两个 channel 几乎同时有数据到达,
select
会随机选择一个case
执行。 - 另一个
case
不会被执行,但它的数据仍然保留在 channel 中。
- 由于两个 channel 几乎同时有数据到达,
- 再次使用
select
监听,此时另一个case
会被执行。
可能的输出:
Received from ch1: message from ch1
Received from ch2: message from ch2
或者:
Received from ch2: message from ch2
Received from ch1: message from ch1
总结:
- 在
select
中,如果多个case
同时满足条件,只有一个会被执行,其余的会被忽略。 - 未执行的
case
的状态会被保留,可以在后续的select
中继续处理。 - 如果需要处理所有满足条件的
case
,可以使用for
循环包裹select
,反复执行直到所有 channel 都被处理完毕。
例如:
for {select {case msg := <-ch1:fmt.Println("Received from ch1:", msg)case msg := <-ch2:fmt.Println("Received from ch2:", msg)default:return // 退出循环}
}
这样可以确保所有满足条件的 case
都被处理。