• go select 使用总结


    转载请注明出处:

      在Go语言中,select语句用于处理多个通道的并发操作。它类似于switch语句,但是select语句用于通信操作,而不是条件判断。select语句会同时监听多个通道的操作,并选择其中一个可用的通道进行操作。 select语句的语法如下:

    复制代码
    select {
        case <-channel1:
            // 执行channel1的操作
        case data := <-channel2:
            // 执行channel2的操作,同时将通道中的数据赋值给data变量
        case channel3 <- data:
            // 将data写入channel3
        default:
            // 当没有任何通道操作时执行default语句
    }
    复制代码

      select语句中可以包含多个case子句,每个case子句表示一个通道操作。<-符号用于从通道中读取数据,channel <- data用于将数据写入通道。 select语句的执行流程为:

    • 如果有多个通道都可以操作,则随机选择一个进行操作。

    • 如果没有任何通道可以操作,则会执行default语句(如果有)。

    • 如果没有default语句,则select语句会阻塞,直到至少有一个通道可以操作。

      下面是一个使用select语句的示例:

    复制代码
    package main
    
    import (
        "fmt"
        "time"
    )
    
    func main() {
        ch1 := make(chan int)
        ch2 := make(chan int)
    
        go func() {
            time.Sleep(time.Second)
            ch1 <- 1
            fmt.Println("ch1 ending")
        }()
    
        go func() {
            time.Sleep(2 * time.Second)
            ch2 <- 2
            fmt.Println("ch2 ending")
        }()
    
        select {
            case data := <-ch1:
                fmt.Println("收到ch1的数据:", data)
            case data := <-ch2:
                fmt.Println("收到ch2的数据:", data)
            case <-time.After(100 * time.Second):
                fmt.Println("超时:没有接收到任何数据")
        }
    }
    复制代码

      在上面的例子中,我们创建了两个通道ch1ch2,并分别在不同的goroutine中向它们发送数据。然后使用select语句监听这两个通道的操作,当其中一个通道可用时,就会执行对应的case语句。

      在这个例子中,由于ch1的数据发送操作会在1秒后执行,而ch2的数据发送操作会在2秒后执行,因此select语句会等待1秒后,执行ch1case语句,输出"收到ch1的数据: 1"。如果我们将ch1的发送操作改为在2秒后执行,那么select语句将会等待2秒后,执行ch2case语句,输出"收到ch2的数据: 2"。

      需要注意的是,select语句的执行顺序是随机的,所以不能依赖于某个通道的操作先于其他通道。这也是使用select语句时需要注意的地方之一。

      如果希望持续监听多个通道的操作,可以将select语句放在一个无限循环中。

    复制代码
    package main
    import (
        "fmt"
        "time"
    )
    func main() {
        channel1 := make(chan int)
        channel2 := make(chan string)
        go func() {
            for i := 0; i < 5; i++ {
                time.Sleep(time.Second)
                channel1 <- i
            }
            close(channel1)
        }()
        go func() {
            for i := 0; i < 5; i++ {
                time.Sleep(time.Second)
                channel2 <- fmt.Sprintf("Message %d", i)
            }
            close(channel2)
        }()
        for {
            select {
            case data1, ok := <-channel1:
                if ok {
                    fmt.Println("Received from channel1:", data1)
                } else {
                    fmt.Println("Channel1 closed")
                    channel1 = nil
                }
            case data2, ok := <-channel2:
                if ok {
                    fmt.Println("Received from channel2:", data2)
                } else {
                    fmt.Println("Channel2 closed")
                    channel2 = nil
                }
            }
            if channel1 == nil && channel2 == nil {
                break
            }
        }
        fmt.Println("Done")
    }
    复制代码

      在这个示例中,创建了两个通道channel1channel2,分别用于发送不同类型的数据。然后分别启动两个goroutine,每个goroutine向对应的通道发送一些数据,然后关闭通道。其运行得结果如图:

     

                  

      上述代码中 ok 是从通道的属性中获取的。在Go语言中,当从通道接收数据时,会返回两个值:接收到的数据和一个表示通道是否已关闭的布尔值。这个布尔值就是ok。 当通道已关闭且没有数据可读取时,会返回通道元素类型的零值和false。当通道还未关闭且有数据可读取时,会返回通道中的数据和true 因此,使用data, ok := <-channel的语法可以同时接收通道中的数据和判断通道是否已关闭。data表示接收到的数据,ok表示通道是否还有数据可读取。如果okfalse,则表示通道已关闭,没有数据可读取。

      在主函数中,我们使用无限循环和select语句来持续监听这两个通道的操作。每次循环时,select语句会选择其中一个可用的通道进行操作。如果通道关闭,我们会将对应的通道设置为nil,以便在后续的循环中跳过该通道的操作。当两个通道都关闭,即channel1channel2都为nil时,我们跳出循环,程序结束。

      运行上述代码,你会看到程序持续监听两个通道的操作,并打印接收到的数据,直到两个通道都关闭。最后,程序输出"Done"并结束。

       

     

     

     

  • 相关阅读:
    ISO20000认证一般要多少钱
    线性表的插入、删除和查询操作
    基于MATLAB开发AUTOSAR软件应用层模块-part9.AUTOSAR工具箱的功能介绍-2
    【Java 语言】Java 和基于 Java 的编程基础 d.运算符
    俄罗斯套娃信封问题
    23. 合并 K 个升序链表
    Waves插件
    欧拉路,欧拉回路
    银河麒麟系统下安装Kingbase数据库
    企业为啥邀请媒体做专访?有哪些注意事项?
  • 原文地址:https://www.cnblogs.com/zjdxr-up/p/17530604.html