【go从入门到精通】select条件控制

作者简介:

        高科先后在 IBM PlatformComputing从事网格计算,淘米网,网易从事游戏服务器开发,拥有丰富的C++,go等语言开发经验,mysql,mongo,redis等数据库,设计模式和网络库开发经验,对战棋类,回合制,moba类页游,手游有丰富的架构设计和开发经验。 (谢谢你的关注)

--------------------------------------------------------------------------------------------------------------------------------

              接着上一篇文章, 【go从入门到精通】if else 条件控制 , 我们再聊一下条件语句的另外一个关键词 select

条件语句select

select 语句

        select 语句类似于 switch 语句,但是和switch又有区别, select语句用于在多个通道操作之间进行选择,可以用于实现非阻塞的通信操作。select语句会等待其中一个通道操作准备就绪(即通道有数据可读或可写),然后执行对应的分支。每个分支必须是一个通道操作,包括发送操作和接收操作,如果没有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或值进行求值。 

实例:
select {
case msg1 := <-ch1:
    fmt.Println("received", msg1)
case msg2 := <-ch2:
    fmt.Println("received", msg2)
case ch3 <- msg3:
    fmt.Println("sent", msg3)
default:
    fmt.Println("no communication ready")
}

以上代码执行结果为:

    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会按顺序从头到尾评估每一个发送和接收的语句。

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

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 

如果你留意一些开源的代码,你就能容易发现其实有很多的select用法,比如toolbox的定时器任务的用法里实际上也在使用select、具体的代码在task.go里的run函数里:

典型用法

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。视需求而定
} 

相关推荐

  1. go入门精通】常量和枚举详解

    2024-03-22 07:34:02       13 阅读
  2. go入门精通】反射的限制

    2024-03-22 07:34:02       16 阅读
  3. go入门精通精通并发编程-协程goroutine

    2024-03-22 07:34:02       12 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-22 07:34:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-22 07:34:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-22 07:34:02       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-22 07:34:02       20 阅读

热门阅读

  1. macOS 合并同名文件夹 按住 Option 键

    2024-03-22 07:34:02       18 阅读
  2. React核心⼊⻔-lesson1

    2024-03-22 07:34:02       18 阅读
  3. 2024.3.21 ARM

    2024-03-22 07:34:02       20 阅读
  4. C++ 函数指针与回调函数

    2024-03-22 07:34:02       24 阅读
  5. 全球化战略中的技术纵深

    2024-03-22 07:34:02       19 阅读
  6. android11 系统的启动流程 的面试题目

    2024-03-22 07:34:02       21 阅读
  7. Python 机器学习 前向后向算法评估观察序列概率

    2024-03-22 07:34:02       21 阅读