• 流程控制之select


    1 select语句

    select语句类似于switch语句,但是select会随机执行一个可运行的case。如果没有case可运行,它将阻塞,直到有case可运行。

    select 是GO中的一个控制结构,类似于通信的switch语句。每个case必须是一个通信操作,要么是发送要么是接收。select随机执行一个可运行的case。如果没有case可运行,它将阻塞,知道有case可运行。一个默认的子句应该总是可运行的。

    语法:

    Go编程语言中select语句的语法如下:

    select {
        case communication clause  :
           statement(s);      
        case communication clause  :
           statement(s);
        /* 你可以定义任意数量的 case */
        default : /* 可选 */
           statement(s);
    }

    以下描述了select语句的语法:

        每个case都必须是一个通信
        所有channel表达式都会被求值
        所有被发送的表达式都会被求值
        如果任意某个通信可以进行,它就执行;其他被忽略。
        如果有多个case都可以运行,Select会随机公平地选出一个执行。其他不会执行。
        否则:
        如果有default子句,则执行该语句。
        如果没有default字句,select将阻塞,直到某个通信可以运行;Go不会重新对channel或值进行求值。

    实例:

    package main
    
    import "fmt"
    
    func main() {
       var c1, c2, c3 chan int
       var i1, i2 int
       select {
          case i1 = <-c1:
             fmt.Printf("received ", i1, " from c1\n")
          case c2 <- i2:
             fmt.Printf("sent ", i2, " to c2\n")
          case i3, ok := (<-c3):  // same as: i3, ok := <-c3
             if ok {
                fmt.Printf("received ", i3, " from c3\n")
             } else {
                fmt.Printf("c3 is closed\n")
             }
          default:
             fmt.Printf("no communication\n")
       }    
    }

    以上代码的执行结果为:

        no communication

    select 可以监听channel的数据流动

    select的用法于switch语法非常类似,由select开始的一个新的选择块,每个选择条件由case语句来描述与switch语句可以选择任何使用相等比较的条件相比,select有比较多的限制,其中最大的一条限制就是每个case语句里必须是一个IO操作

        select { //不停的在这里检测
        case <-chanl : //检测有没有数据可以读
        //如果chanl成功读取到数据,则进行该case处理语句
        case chan2 <- 1 : //检测有没有可以写
        //如果成功向chan2写入数据,则进行该case处理语句
    
    
        //假如没有default,那么在以上两个条件都不成立的情况下,就会在此阻塞//一般default会不写在里面,select中的default子句总是可运行的,因为会很消耗CPU资源
        default:
        //如果以上都没有符合条件,那么则进行default处理流程
        }

    在一个select语句中,Go会按顺序从头到尾评估美国以发送和接收的语句。

    如果其中的任意一个语句可以继续执行(即没有被阻塞),那么就从那些可以执行的语句中任意选择一条来使用,如果没有任意一条语句可以执行(即所有通道都被阻塞),那么有两种可能的情况:1.如果给出了default语句,那么就会执行default的流程,同时程序的执行会从select语句后的语句中恢复。2.如果没有default语句,那么select语句将被阻塞,知道至少有一个case可以进行下去。

    1.2 golang select的使用及典型用法

    基本使用

    select是Go中的一个控制结构,类似于switch语句,用于处理异步IO操作。select会监听case语句中channel的读写操作,当case中channel读写操作为非阻塞状态(即能读写)时,将会触发相应的动作。 select中的case语句必须是一个channel操作

    select中的default子句总是可运行的。

    如果有多个case都可以运行,select会随机公平地选出一个执行,其他不会执行。

    如果没有可运行的case语句,且有default语句,那么就会执行default的动作。

    如果没有可运行的case语句,且没有default语句,select将阻塞,直到某个case通信可以运行

    例如:

    package main
    
    import "fmt"
    
    func main() {
       var c1, c2, c3 chan int
       var i1, i2 int
       select {
          case i1 = <-c1:
             fmt.Printf("received ", i1, " from c1\n")
          case c2 <- i2:
             fmt.Printf("sent ", i2, " to c2\n")
          case i3, ok := (<-c3):  // same as: i3, ok := <-c3
             if ok {
                fmt.Printf("received ", i3, " from c3\n")
             } else {
                fmt.Printf("c3 is closed\n")
             }
          default:
             fmt.Printf("no communication\n")
       }    
    }
    
    //输出:no communication

    1.3 典型用法

    1 超时判断

    //比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行
    var resChan = make(chan int)
    // do request
    func test() {
        select {
        case data := <-resChan:
            doData(data)
        case <-time.After(time.Second * 3):
            fmt.Println("request time out")
        }
    }
    
    func doData(data int) {
        //...
    }

    2 退出

    //主线程(协程)中如下:
    var shouldQuit=make(chan struct{})
    fun main(){
        {
            //loop
        }
        //...out of the loop
        select {
            case <-c.shouldQuit:
                cleanUp()
                return
            default:
            }
        //...
    }
    
    //再另外一个协程中,如果运行遇到非法操作或不可处理的错误,就向shouldQuit发送数据通知程序停止运行
    close(shouldQuit)

    3.判断channel是否阻塞

    //在某些情况下是存在不希望channel缓存满了的需求的,可以用如下方法判断
    ch := make (chan int, 5)
    //...
    data:=0
    select {
    case ch <- data:
    default:
        //做相应操作,比如丢弃data。视需求而定
    }
  • 相关阅读:
    .Net Core主机配置
    .NET Core 初识
    控制反转IOC,依赖注入DI理解
    依赖倒置原则解析,理解面向抽象编程
    工厂模式
    IOC 概念
    利用Comparator排序
    使用Integer类实现二叉树排序
    先按成绩由高到低,相等则按年龄由低到高
    对象销毁之前进行某些操作
  • 原文地址:https://www.cnblogs.com/ltyc/p/16354852.html
Copyright © 2020-2023  润新知