GO语言网络编程(并发编程)select

GO语言网络编程(并发编程)select

1、select

1.1.1 select多路复用

在某些场景下我们需要同时从多个通道接收数据。通道在接收数据时,如果没有数据可以接收将会发生阻塞。你也许会写出如下代码使用遍历的方式来实现:

go 复制代码
for{
    // 尝试从ch1接收值
    data, ok := <-ch1
    // 尝试从ch2接收值
    data, ok := <-ch2
    ...
}

这种方式虽然可以实现从多个通道接收值的需求,但是运行性能会差很多。为了应对这种场景,Go内置了select关键字,可以同时响应多个通道的操作。

select的使用类似于switch语句,它有一系列case分支和一个默认的分支。每个case会对应一个通道的通信(接收或发送)过程。select会一直等待,直到某个case的通信操作完成时,就会执行case分支对应的语句。具体格式如下:

go 复制代码
select {
case <-chan1:
   // 如果chan1成功读到数据,则进行该case处理语句
case chan2 <- 1:
   // 如果成功向chan2写入数据,则进行该case处理语句
default:
   // 如果上面都没有成功,则进入default处理流程
}
  • select可以同时监听一个或多个channel,直到其中一个channel ready
go 复制代码
package main

import (
   "fmt"
   "time"
)

func test1(ch chan string) {
   time.Sleep(time.Second * 5)
   ch <- "test1"
}
func test2(ch chan string) {
   time.Sleep(time.Second * 2)
   ch <- "test2"
}

func main() {
   // 2个管道
   output1 := make(chan string)
   output2 := make(chan string)
   // 跑2个子协程,写数据
   go test1(output1)
   go test2(output2)
   // 用select监控
   select {
   case s1 := <-output1:
      fmt.Println("s1=", s1)
   case s2 := <-output2:
      fmt.Println("s2=", s2)
   }
}
  • 如果多个channel同时ready,则随机选择一个执行
go 复制代码
package main

import (
   "fmt"
)

func main() {
   // 创建2个管道
   int_chan := make(chan int, 1)
   string_chan := make(chan string, 1)
   go func() {
      //time.Sleep(2 * time.Second)
      int_chan <- 1
   }()
   go func() {
      string_chan <- "hello"
   }()
   select {
   case value := <-int_chan:
      fmt.Println("int:", value)
   case value := <-string_chan:
      fmt.Println("string:", value)
   }
   fmt.Println("main结束")
}
  • 可以用于判断管道是否存满
go 复制代码
package main

import (
   "fmt"
   "time"
)

// 判断管道有没有存满
func main() {
   // 创建管道
   output1 := make(chan string, 10)
   // 子协程写数据
   go write(output1)
   // 取数据
   for s := range output1 {
      fmt.Println("res:", s)
      time.Sleep(time.Second)
   }
}

func write(ch chan string) {
   for {
      select {
      // 写数据
      case ch <- "hello":
         fmt.Println("write hello")
      default:
         fmt.Println("channel full")
      }
      time.Sleep(time.Millisecond * 500)
   }
}
相关推荐
luj_17687 小时前
残熵算法实时化三大瓶颈突破
c语言·开发语言·网络·经验分享·算法
吴懿不在7 小时前
某次热身赛re方向wp WORDS 51,500 READ 172 MIN base64,
网络
RestCloud8 小时前
借助ETL工具,实现AI智能体+数据的落地
数据仓库·人工智能·sql·etl·etlcloud·数据集成平台·java脚本
小林ixn10 小时前
从“玩具工具”到“跨语言利器”:MCP 协议实战解析
运维·服务器·网络
上海云盾-小余10 小时前
网站频繁遭遇 SQL 注入溯源与原生漏洞修复全流程总结
数据库·sql
2603_9547083112 小时前
全维度容错设计,打造微电网安全运行屏障
服务器·网络·数据库·人工智能·分布式·安全
青岛前景互联信息技术有限公司13 小时前
以新标准为底座,前景互联打造高危场景智能接处警新体系
大数据·网络·人工智能
大飞记Python13 小时前
Linux命令速查手册(测试开发4年实战总结,附PDF)
linux·网络·pdf
AFinalStone13 小时前
Android 7系统网络(四)Native层(下)—netd Controller详解
android·网络
Sirius Wu13 小时前
OpenClaw(UpClaw)三层Tool全链路治理深度详解
网络·人工智能·架构·aigc