Go语言使用select监听多个channel的示例详解

作者:

文章目录
  • 在 Go 的并发编程中,channel 是协程间通信的核心工具。但当你需要同时从多个 Channel 中接收数据,或者在特定时间内做出响应,select 就派上了大用场。 它类似于网络编程中的 select/poll/epoll,用于监听多个 IO 操作的就绪状态,只不过这里的 IO 是 Channel 的读写操作。
  • 我们将构建一个并发任务监听系统,实现以下目标: 启动多个任务(Goroutine),分别向不同的 Channel 写入结果 使用 select 监听多个 Channel,响应哪个就处理哪个 实现超时处理 实现 Channel 关闭退出机制
  • package main import ( “fmt” “math/rand” “time” ) func task(name string, delay time.Duration, ch chan<- string) { time.Sleep(delay) ch <- fmt.Sprintf(“任务 %s 完成(耗时 %v)”, name, delay) } func main() { rand.Seed(time.Now().UnixNano()) task1Ch := make(chan string) task2Ch := make(chan string) // 启动两个任务 go task(“A”, time.Duration(rand.Intn(2000))*time.Millisecond, task1Ch) go task(“B”, time.Duration(rand.Intn(2000))*time.Millisecond, task2Ch) // 使用 select 监听两个任务完成情况 timeout := time.After(2 * time.Second) // 超时设置 for i := 0; i < 2; i++ { select { case res := <-task1Ch: fmt.Println(“[监听] 收到任务1结果:”, res) case res := <-task2Ch: fmt.Println(“[监听] 收到任务2结果:”, res) case <-timeout: fmt.Println(“[监听] 等待超时!”) return } } fmt.Println(“主程序退出。”) }
  • 一次运行输出: [监听] 收到任务2结果: 任务 B 完成(耗时 1.379s)[监听] 收到任务1结果: 任务 A 完成(耗时 1.962s)主程序退出。 另一次运行(任务没完成): [监听] 等待超时!
  • select 与 Channel 联合使用,可以应用于非常多的高并发场景: 场景 用法说明 多任务结果优先处理 谁先完成就处理谁 多个服务节点返回最快结果 服务冗余设计中的快速返回策略 实现“心跳检测”或“任务超时” 每个协程都有监听超时 Channel,任务不响应就退出 限制任务处理时间(防止卡死) 结合 context.WithTimeout() 更可靠
  • func main() { dataCh := make(chan string) quitCh := make(chan bool) // 模拟异步数据流 go func() { for i := 0; i < 5; i++ { dataCh <- fmt.Sprintf(“数据包 #%d”, i) time.Sleep(time.Millisecond * 500) } quitCh <- true }() for { select { case msg := <-dataCh: fmt.Println(“接收数据:”, msg) case <-quitCh: fmt.Println(“任务结束,退出监听循环”) return case <-time.After(1 * time.Second): fmt.Println(“1秒无数据,超时处理…”) } } }
  • 通过本案例你学会了: 如何使用 select 同时监听多个 Channel 如何实现超时机制(time.After) 如何在主线程中等待异步任务完成 如何构建可扩展的并发通信模型 select 是 Go 并发编程的核心工具之一,它让我们能够优雅地处理多路异步事件,是构建高性能系统的利器。 到此这篇关于Go语言使用select监听多个channel的示例详解的文章就介绍到这了,更多相关Go select监听hannel内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Go语言面试题之select和channel的用法 Golang的select多路复用及channel使用操作 详解如何在Golang中监听多个channel 详解Golang中Channel的高级用法 Go 语言 select 的实现原理解析 Golang中的select语句及其应用实例
  • 目录
    • 一、前言:为什么要使用select
    • 二、实战目标
    • 三、案例代码:监听两个任务结果和超时
    • 四、运行示例
    • 五、重点解析:Go 中的select
      • 1.select的行为特性
      • 2. 实现超时机制
      • 3. 非阻塞通道监听(可选)
    • 六、延伸应用场景
      • 七、完整示例:结合for-select实现循环监听
        • 八、总结

          在 Go 的并发编程中,channel 是协程间通信的核心工具。但当你需要同时从多个 Channel 中接收数据,或者在特定时间内做出响应,select 就派上了大用场。

          它类似于网络编程中的 select/poll/epoll,用于监听多个 IO 操作的就绪状态,只不过这里的 IO 是 Channel 的读写操作。

          我们将构建一个并发任务监听系统,实现以下目标:

          • 启动多个任务(Goroutine),分别向不同的 Channel 写入结果
          • 使用 select 监听多个 Channel,响应哪个就处理哪个
          • 实现超时处理
          • 实现 Channel 关闭退出机制

          package main
          
          import (
              "fmt"
              "math/rand"
              "time"
          )
          
          func task(name string, delay time.Duration, ch chan<- string) {
              time.Sleep(delay)
              ch <- fmt.Sprintf("任务 %s 完成(耗时 %v)", name, delay)
          }
          
          func main() {
              rand.Seed(time.Now().UnixNano())
          
              task1Ch := make(chan string)
              task2Ch := make(chan string)
          
              // 启动两个任务
              go task("A", time.Duration(rand.Intn(2000))*time.Millisecond, task1Ch)
              go task("B", time.Duration(rand.Intn(2000))*time.Millisecond, task2Ch)
          
              // 使用 select 监听两个任务完成情况
              timeout := time.After(2 * time.Second) // 超时设置
          
              for i := 0; i < 2; i++ {
                  select {
                  case res := <-task1Ch:
                      fmt.Println("[监听] 收到任务1结果:", res)
                  case res := <-task2Ch:
                      fmt.Println("[监听] 收到任务2结果:", res)
                  case <-timeout:
                      fmt.Println("[监听] 等待超时!")
                      return
                  }
              }
          
              fmt.Println("主程序退出。")
          }
          

          一次运行输出:

          [监听] 收到任务2结果: 任务 B 完成(耗时 1.379s)
          [监听] 收到任务1结果: 任务 A 完成(耗时 1.962s)
          主程序退出。

          另一次运行(任务没完成):

          [监听] 等待超时!

          随机选择一个可用的 case 执行(如果多个都可读)

          如果没有任何 case 准备好,则阻塞,除非有 default

          可以结合 time.After 实现超时控制

          timeout := time.After(2 * time.Second)
          

          这是 Go 提供的标准库能力,会在 2 秒后向 timeout 这个只读通道发送一个时间值,结合 select 使用非常方便。

          select {
          case msg := <-ch:
              fmt.Println("收到消息:", msg)
          default:
              fmt.Println("没有消息,非阻塞处理")
          }
          

          select 与 Channel 联合使用,可以应用于非常多的高并发场景:

          场景 用法说明
          多任务结果优先处理 谁先完成就处理谁
          多个服务节点返回最快结果 服务冗余设计中的快速返回策略
          实现“心跳检测”或“任务超时” 每个协程都有监听超时 Channel,任务不响应就退出
          限制任务处理时间(防止卡死) 结合 context.WithTimeout() 更可靠

          func main() {
              dataCh := make(chan string)
              quitCh := make(chan bool)
          
              // 模拟异步数据流
              go func() {
                  for i := 0; i < 5; i++ {
                      dataCh <- fmt.Sprintf("数据包 #%d", i)
                      time.Sleep(time.Millisecond * 500)
                  }
                  quitCh <- true
              }()
          
              for {
                  select {
                  case msg := <-dataCh:
                      fmt.Println("接收数据:", msg)
                  case <-quitCh:
                      fmt.Println("任务结束,退出监听循环")
                      return
                  case <-time.After(1 * time.Second):
                      fmt.Println("1秒无数据,超时处理...")
                  }
              }
          }
          

          通过本案例你学会了:

          • 如何使用 select 同时监听多个 Channel
          • 如何实现超时机制(time.After
          • 如何在主线程中等待异步任务完成
          • 如何构建可扩展的并发通信模型

          select 是 Go 并发编程的核心工具之一,它让我们能够优雅地处理多路异步事件,是构建高性能系统的利器。

          到此这篇关于Go语言使用select监听多个channel的示例详解的文章就介绍到这了,更多相关Go select监听hannel内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!

          您可能感兴趣的文章:

          • Go语言面试题之select和channel的用法
          • Golang的select多路复用及channel使用操作
          • 详解如何在Golang中监听多个channel
          • 详解Golang中Channel的高级用法
          • Go 语言 select 的实现原理解析
          • Golang中的select语句及其应用实例

          站内搜索