golang中 select同时有多个case满足时的讨论
在 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 main
import (
"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 监听多个 channel
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")
}
// 再次使用 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 都被处理。
Do not communicate by sharing memory; instead, share memory by communicating.

浙公网安备 33010602011771号