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


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

    1、select

    1.1.1 select多路复用

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

    for{
        // 尝试从ch1接收值
        data, ok := <-ch1
        // 尝试从ch2接收值
        data, ok := <-ch2
        …
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

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

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

    select {
    case <-chan1:
       // 如果chan1成功读到数据,则进行该case处理语句
    case chan2 <- 1:
       // 如果成功向chan2写入数据,则进行该case处理语句
    default:
       // 如果上面都没有成功,则进入default处理流程
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • select可以同时监听一个或多个channel,直到其中一个channel ready
    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)
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 如果多个channel同时ready,则随机选择一个执行
    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结束")
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 可以用于判断管道是否存满
    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)
       }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
  • 相关阅读:
    Mysql_Note7
    电脑电源灯一闪一闪开不了机怎么办
    【刷题笔记10.2】LeetCode: 罗马数字转整数
    11、【Qlib】【主要组件】元控制器:元任务、元数据集和元模型
    ESP8266-Arduino编程实例-开发环境搭建(基于Arduino IDE)
    C++-哈希Hash
    基于Yolov8的野外烟雾检测(2):多维协作注意模块MCA,效果秒杀ECA、SRM、CBAM等 | 2023.9最新发布
    泛型的基础 装箱拆箱
    你这个视频背景太假了?
    函数探秘:深入理解C语言函数,实现高效模块化编程
  • 原文地址:https://blog.csdn.net/qq_44139121/article/details/132809381