Go中select多路复用的实现示例

Written by

in

文章目录
  • select 类似于 switch 语句,但它用于监听多个通道的发送/接收操作。一旦其中任意一个通道准备就绪,select 就会执行相应的语句块。
  • 随机选择:如果多个 case 同时满足,Go 会随机选择一个执行,避免饥饿。 阻塞行为:当没有任何 case 可以运行时,select 会阻塞,除非有 default。 可配合 for 使用:实现多路轮询、协程调度等高级用法。
  • select 搭配 time.After() 可实现通道的超时控制: select { case msg := <-ch: fmt.Println(“收到消息:”, msg) case <-time.After(2 * time.Second): fmt.Println(“超时未收到”) } 实用场景: 网络请求超时 等待任务执行完成 控制并发阻塞时间
  • select { case msg := <-ch: fmt.Println(“收到:”, msg) default: fmt.Println(“没有收到任何数据”) } 不等待,立即返回默认分支。
  • 配合 range 和 select,可以优雅处理通道关闭: for { select { case msg, ok := <-ch: if !ok { fmt.Println(“通道已关闭”) return } fmt.Println(“收到:”, msg) } }
  • func merge(ch1, ch2 <-chan string) <-chan string { out := make(chan string) go func() { for { select { case msg := <-ch1: out <- msg case msg := <-ch2: out <- msg } } }() return out } ✅ 实现“扇入”(fan-in)模式,将多个输入流合并成一个输出。
  • 功能 是否支持 同时监听多个通道 ✅ 随机选择就绪的通道执行 ✅ 支持默认分支防止阻塞 ✅ 可实现超时控制与轮询 ✅ 实现非阻塞收发或关闭判断 ✅
  • 为所有关键的通道通信加上 select 和超时控制,避免协程泄漏。 避免使用 select 轮询空通道导致死循环。 多通道合并、拆分时,配合 select 和 sync.WaitGroup 效果更佳。 到此这篇关于Go中select多路复用的实现示例的文章就介绍到这了,更多相关Go select多路复用内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客!  您可能感兴趣的文章: Golang的select多路复用及channel使用操作
  • 目录
    • 一、什么是select
      • 基本语法:
    • 二、select 使用示例
      • 示例1:监听多个通道输入
    • 三、select的特性
      • 四、使用select实现超时机制
        • 五、非阻塞通信:使用default
          • 六、监听通道关闭
            • 七、实践:合并多个输入通道
              • 八、小结
                • 实战建议

                  select 是 Go 并发编程中非常强大的语法结构,它允许程序同时等待多个通道操作的完成,从而实现多路复用机制,是协程调度、超时控制、通道竞争等场景的核心工具。

                  select 类似于 switch 语句,但它用于监听多个通道的发送/接收操作。一旦其中任意一个通道准备就绪,select 就会执行相应的语句块。

                  select {
                  case val := <-ch1:
                      // ch1 可读时执行
                  case ch2 <- data:
                      // ch2 可写时执行
                  default:
                      // 所有通道都不准备好时执行(可选)
                  }
                  

                  func main() {
                      ch1 := make(chan string)
                      ch2 := make(chan string)
                  
                      go func() {
                          time.Sleep(1 * time.Second)
                          ch1 <- "消息来自 ch1"
                      }()
                  
                      go func() {
                          time.Sleep(2 * time.Second)
                          ch2 <- "消息来自 ch2"
                      }()
                  
                      select {
                      case msg1 := <-ch1:
                          fmt.Println(msg1)
                      case msg2 := <-ch2:
                          fmt.Println(msg2)
                      }
                  }
                  

                  输出(大概率):

                  消息来自 ch1

                  谁先准备好,谁被执行。

                  • 随机选择:如果多个 case 同时满足,Go 会随机选择一个执行,避免饥饿。
                  • 阻塞行为:当没有任何 case 可以运行时,select 会阻塞,除非有 default
                  • 可配合 for 使用:实现多路轮询、协程调度等高级用法。

                  select 搭配 time.After() 可实现通道的超时控制:

                  select {
                  case msg := <-ch:
                      fmt.Println("收到消息:", msg)
                  case <-time.After(2 * time.Second):
                      fmt.Println("超时未收到")
                  }
                  

                  实用场景:

                  • 网络请求超时
                  • 等待任务执行完成
                  • 控制并发阻塞时间

                  select {
                  case msg := <-ch:
                      fmt.Println("收到:", msg)
                  default:
                      fmt.Println("没有收到任何数据")
                  }
                  

                  不等待,立即返回默认分支。

                  配合 range 和 select,可以优雅处理通道关闭:

                  for {
                      select {
                      case msg, ok := <-ch:
                          if !ok {
                              fmt.Println("通道已关闭")
                              return
                          }
                          fmt.Println("收到:", msg)
                      }
                  }
                  

                  func merge(ch1, ch2 <-chan string) <-chan string {
                      out := make(chan string)
                      go func() {
                          for {
                              select {
                              case msg := <-ch1:
                                  out <- msg
                              case msg := <-ch2:
                                  out <- msg
                              }
                          }
                      }()
                      return out
                  }
                  

                  ✅ 实现“扇入”(fan-in)模式,将多个输入流合并成一个输出。

                  功能 是否支持
                  同时监听多个通道
                  随机选择就绪的通道执行
                  支持默认分支防止阻塞
                  可实现超时控制与轮询
                  实现非阻塞收发或关闭判断

                  • 为所有关键的通道通信加上 select 和超时控制,避免协程泄漏。
                  • 避免使用 select 轮询空通道导致死循环。
                  • 多通道合并、拆分时,配合 select 和 sync.WaitGroup 效果更佳。

                  到此这篇关于Go中select多路复用的实现示例的文章就介绍到这了,更多相关Go select多路复用内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 

                  您可能感兴趣的文章:

                  • Golang的select多路复用及channel使用操作

                  站内搜索