golang中 select同时有多个case满足时的讨论


在 Go 的 select 语句中,如果多个 case 同时满足条件,Go 会随机选择一个执行,而其他满足条件的 case 不会被执行。也就是说,select 语句只会执行一个 case,其余的 case 会被忽略。

关键点:

  1. select 的执行机制

    • select 会检查所有 case 的条件。
    • 如果有多个 case 满足条件(例如多个 channel 同时有数据可读或可写),Go 会随机选择一个 case 执行。
    • 其他满足条件的 case 不会被执行,也不会被“保存”到下一次 select
  2. 未执行的 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")
	}
}

代码说明:

  1. 创建了两个 channel ch1ch2
  2. 启动两个 goroutine,分别向 ch1ch2 发送数据,发送操作有 100 毫秒的延迟。
  3. 使用 select 监听 ch1ch2
    • 由于两个 channel 几乎同时有数据到达,select 会随机选择一个 case 执行。
    • 另一个 case 不会被执行,但它的数据仍然保留在 channel 中。
  4. 再次使用 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 都被处理。

posted @   guanyubo  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
历史上的今天:
2024-01-24 Linux网络编程基础API
点击右上角即可分享
微信分享提示