Go语言中select使用详解

Written by

in

文章目录
  • select 是 Go 中用于 多路 channel 操作 的控制结构,它可以监听多个 channel 的发送与接收操作,当其中某一个可以进行时就执行对应的语句,从而实现非阻塞并发通信。
  • select { case val := <-ch1: // ch1 可读时执行 case ch2 <- 100: // ch2 可写时执行 default: // 所有 channel 都阻塞时执行(可选) } 每个 case 必须是 发送(ch <- val)或接收(val := <-ch) 只会执行一个可操作的 case(如果多个都可以随机挑一个) 如果都阻塞,且没有 default,select 会阻塞等待 如果包含 default,它会立即执行,哪怕其他 case 可能之后才可操作
  • 行为 描述 随机调度 多个 case 同时可用时随机选择一个执行(防止饥饿) 阻塞等待 所有 case 阻塞时,select 自身也阻塞 default 分支 所有 case 阻塞时立即执行,避免阻塞 只选一个 同时满足多个时只执行其中一个
  • func producer(ch chan int) { for i := 0; i < 5; i++ { ch <- i } close(ch) } ​ func consumer(ch chan int, done chan struct{}) { for { select { case val, ok := <-ch: if !ok { done <- struct{}{} return } fmt.Println(“消费:”, val) } } }
  • for { select { case msg := <-ch: fmt.Println(“收到:”, msg) case <-time.After(5 * time.Second): fmt.Println(“超时退出”) return } }
  • 陷阱 描述 忘记 default 导致阻塞 如果所有 case 阻塞,select 也阻塞 无限阻塞 select 中所有 channel 永远不会可用 channel 已关闭 向已关闭通道写入会 panic,应特别小心 超时误用 使用 time.After() 时,不要在循环里频繁创建新 channel,否则内存泄漏 🔍 解决建议:使用 time.NewTimer,并复用 timer。
  • 建议 原因 用 select 实现超时控制 比较优雅且非阻塞 select + default 实现非阻塞通信 避免 goroutine 卡死 用 select + context.Done() 控制退出 在大型系统中更适合
  • ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() ​ ch := make(chan int) ​ go func() { time.Sleep(2 * time.Second) ch <- 42 }() ​ select { case <-ctx.Done(): fmt.Println(“操作取消/超时:”, ctx.Err()) case val := <-ch: fmt.Println(“接收到数据:”, val) }
  • 维度 说明 功能 实现 channel 的多路复用监听 优点 非阻塞、高效、优雅处理通信控制 结合 time.After、context、default 最佳组合 场景 goroutine 退出、任务超时、并发协程间通信控制等 到此这篇关于Go语言中select使用的文章就介绍到这了,更多相关Go select详解内容请搜索风君子博客以前的文章或继续浏览下面的相关文章希望大家以后多多支持风君子博客! 您可能感兴趣的文章: Go语言中Select语句用法实例 golang中的select关键字用法总结 简介Go语言中的select语句的用法 深入浅出Golang中select的实现原理 go select的用法 Golang关键字select的常用用法总结 详解golang开发中select多路选择 golang中select语句的简单实例
  • 目录
    • 什么是 select?
    • 基本语法
    • 使用场景举例
      • 1. 监听多个 channel 的数据
      • 2. 实现超时机制
      • 3. 非阻塞发送或接收(default 分支)
      • 4. 检测通道是否关闭
    • select 的行为特点
      • 与 goroutine 配合:生产者/消费者模型
        • select + for:常见循环写法
          • select 常见陷阱
            • 实战建议
              • 例子:context 控制退出(推荐生产使用)
                • 总结

                  select 是 Go 中用于 多路 channel 操作 的控制结构,它可以监听多个 channel 的发送与接收操作,当其中某一个可以进行时就执行对应的语句,从而实现非阻塞并发通信。

                  select {
                  case val := <-ch1:
                      // ch1 可读时执行
                  case ch2 <- 100:
                      // ch2 可写时执行
                  default:
                      // 所有 channel 都阻塞时执行(可选)
                  }
                  • 每个 case 必须是 发送(ch <- val)或接收(val := <-ch)

                  • 只会执行一个可操作的 case(如果多个都可以随机挑一个)

                  • 如果都阻塞,且没有 defaultselect 会阻塞等待

                  • 如果包含 default,它会立即执行,哪怕其他 case 可能之后才可操作

                  select {
                  case msg1 := <-ch1:
                      fmt.Println("收到 ch1:", msg1)
                  case msg2 := <-ch2:
                      fmt.Println("收到 ch2:", msg2)
                  }

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

                  time.After 返回一个 channel,在指定时间后变为可读,实现优雅的 timeout。

                  select {
                  case ch <- data:
                      fmt.Println("发送成功")
                  default:
                      fmt.Println("channel 满,放弃发送")
                  }

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

                  行为 描述
                  随机调度 多个 case 同时可用时随机选择一个执行(防止饥饿)
                  阻塞等待 所有 case 阻塞时,select 自身也阻塞
                  default 分支 所有 case 阻塞时立即执行,避免阻塞
                  只选一个 同时满足多个时只执行其中一个

                  func producer(ch chan int) {
                      for i := 0; i < 5; i++ {
                          ch <- i
                      }
                      close(ch)
                  }
                  ​
                  func consumer(ch chan int, done chan struct{}) {
                      for {
                          select {
                          case val, ok := <-ch:
                              if !ok {
                                  done <- struct{}{}
                                  return
                              }
                              fmt.Println("消费:", val)
                          }
                      }
                  }

                  for {
                      select {
                      case msg := <-ch:
                          fmt.Println("收到:", msg)
                      case <-time.After(5 * time.Second):
                          fmt.Println("超时退出")
                          return
                      }
                  }

                  陷阱 描述
                  忘记 default 导致阻塞 如果所有 case 阻塞,select 也阻塞
                  无限阻塞 select 中所有 channel 永远不会可用
                  channel 已关闭 向已关闭通道写入会 panic,应特别小心
                  超时误用 使用 time.After() 时,不要在循环里频繁创建新 channel,否则内存泄漏

                  🔍 解决建议:使用 time.NewTimer,并复用 timer。

                  建议 原因
                  用 select 实现超时控制 比较优雅且非阻塞
                  select + default 实现非阻塞通信 避免 goroutine 卡死
                  用 select + context.Done() 控制退出 在大型系统中更适合

                  ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
                  defer cancel()
                  ​
                  ch := make(chan int)
                  ​
                  go func() {
                      time.Sleep(2 * time.Second)
                      ch <- 42
                  }()
                  ​
                  select {
                  case <-ctx.Done():
                      fmt.Println("操作取消/超时:", ctx.Err())
                  case val := <-ch:
                      fmt.Println("接收到数据:", val)
                  }

                  维度 说明
                  功能 实现 channel 的多路复用监听
                  优点 非阻塞、高效、优雅处理通信控制
                  结合 time.After、context、default 最佳组合
                  场景 goroutine 退出、任务超时、并发协程间通信控制等

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

                  您可能感兴趣的文章:

                  • Go语言中Select语句用法实例
                  • golang中的select关键字用法总结
                  • 简介Go语言中的select语句的用法
                  • 深入浅出Golang中select的实现原理
                  • go select的用法
                  • Golang关键字select的常用用法总结
                  • 详解golang开发中select多路选择
                  • golang中select语句的简单实例

                  站内搜索