Go-Select

作者: 骑蜗上高速 | 来源:发表于2019-12-25 17:12 被阅读0次

    Go里面的一个关键字,用于监听channel上的数据流动。select语句里面的每条case语句必须是一个IO操作。

    select {
    case <- chan1;
            //如果chan1成功读 取到数据,则进行该case语句处理。
    case chan2 <- 1;
            //如果成功向chan2中写入数据,则进行case语句处理。
    default;
            //如果上面都没有成功,则进入default语句处理,通常不用(会产生忙轮训)
    }
    

    代码示例:

    package main
    import (
        "fmt"
        "runtime"
        "time"
    )
    func main () {
        //定义两个channel
        ch := make(chan int)//用于通信
        quit := make(chan bool)//用于判断是否退出
        //新建一个子goroutine,用于channel写
        go func() {
            for i :=0; i < 5; i++ {
                ch <- i
                time.Sleep(time.Second)
            }
            close(ch)//关闭channel
            quit <- true//通知主goroutine是否退出
            runtime.Goexit()
        }()
        //主goroutine用于读取
        for  {
            select {
            case  num := <- ch :
                fmt.Println("读到:",num)
            case  <- quit:
                return
            }
            fmt.Println("###############")
        }
    }
    

    输出:

    读到: 0
    ###############
    读到: 1
    ###############
    读到: 2
    ###############
    读到: 3
    ###############
    读到: 4
    ###############
    

    斐波那契数列:

    package main
    import (
        "fmt"
        "runtime"
    )
    //打印输出Fibonacci
    func fibonacci (ch <- chan int,quit <- chan bool)  {
        for {
            select {
            case num :=  <- ch://从管道中读取数据
                fmt.Print(num," ")
            case <- quit:
                runtime.Goexit()//退出子goroutine
            }
        }
    }
    func main () {
        //定义两个channel
        ch := make(chan int)//用于通信
        quit := make(chan bool)//用于判断主goroutine是否退出
        go fibonacci(ch,quit)//打印输出Fibonacci
        //主goroutine用于计算
        x,y := 1,1
        for i := 0; i < 20; i++ {
            ch <- x
            x, y = y, x + y
        }
        quit <- true
    }
    

    注意事项:
    1、监听的case中,没有满足的监听条件,阻塞。
    2、监听的case中,有多个满足监听条件,任选一个执行。
    3、可以使用default来处理所有的case都不满足的条件的状况,通常不用(会产生忙轮训)。
    4、select自身不带有循环机制,需要借助外层的for循环来监听。
    5、break只能跳出select,类似于switch中的用法。不能使用break跳出主goroutine,如果要跳 出子goroutine,可以使用runtime.Goexit()

    超时:

    package main
    import (
        "fmt"
        "time"
    )
    func main () {
        ch := make(chan int)
        quit := make(chan bool)
        //timer := time.NewTimer(time.Second*3)
        go func() {
            for {
                select {
                case num := <- ch: //这里阻塞了,因为没有写
                fmt.Println("num=",num)
                //case <- timer.C: //等待3秒后,把系统时间读取出来
                case <- time.After(3*time.Second)://等待3秒后,把系统时间读取出来
                    fmt.Println("超时")
                     quit <- true//判断是否退出
                     break
                }
            }
        }()
    
         <- quit//主goroutine从管道中读取
    }
    

    相关文章

      网友评论

        本文标题:Go-Select

        本文链接:https://www.haomeiwen.com/subject/ktococtx.html