百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分类 > 正文

select...case语句详解

ztj100 2025-01-01 23:52 18 浏览 0 评论

select 语句

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

select 是Go中的一个控制结构, 类似于用于通信的switch语句。每个case必须是一个通信操作, 要么是发送要么是接收。

select 随机执行一个可运行的case。如果没有case可运行, 它将阻塞, 直到有case可运行。一个默认的子句应该总是可运行的。

语法:

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可以进行下去。

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.超时判断

//比如在下面的场景中,使用全局resChan来接受response,如果时间超过3S,resChan中还没有数据返回,则第二条case将执行

package main
import (
"fmt"
"time"
)
var resChan = make(chan int)
// do request
func main() {
select {
case data := <-resChan:
doData(data)
case <-time.After(time.Second * 3): // 超时判断
fmt.Println("request time out")
}
}
func doData(data int) {
fmt.Println(data)
}

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

4 select...case 匹配多个通道问题?

package main
import (
"fmt"
"time"
)
func main() {
timeout := make(chan bool, 1)
ch := make(chan int)
go func() {
time.Sleep(1 * time.Second)
timeout <- true
}()
go func() {
time.Sleep(13 * time.Second)
ch <- 1
}()
// select...case 专门用于匹配通道
select {
// 这里是匹配两个通道, 是分开执行的,不是匹配两个值的效果(不同于PHP、js的语法效果)
case <-ch:
// fmt.Println("ch 通道")
case <-timeout:
fmt.Println("timeout!")
}
/*
// select case 无法匹配两个通道, 是错误的语法
// switch...case 可以匹配多个值(非通道)
select{
case <-ch, <-timeout:
fmt.Println("timeout")
}
*/
}

相关推荐

SpringBoot整合SpringSecurity+JWT

作者|Sans_https://juejin.im/post/5da82f066fb9a04e2a73daec一.说明SpringSecurity是一个用于Java企业级应用程序的安全框架,主要包含...

「计算机毕设」一个精美的JAVA博客系统源码分享

前言大家好,我是程序员it分享师,今天给大家带来一个精美的博客系统源码!可以自己买一个便宜的云服务器,当自己的博客网站,记录一下自己学习的心得。开发技术博客系统源码基于SpringBoot,shiro...

springboot教务管理系统+微信小程序云开发附带源码

今天给大家分享的程序是基于springboot的管理,前端是小程序,系统非常的nice,不管是学习还是毕设都非常的靠谱。本系统主要分为pc端后台管理和微信小程序端,pc端有三个角色:管理员、学生、教师...

SpringBoot+LayUI后台管理系统开发脚手架

源码获取方式:关注,转发之后私信回复【源码】即可免费获取到!项目简介本项目本着避免重复造轮子的原则,建立一套快速开发JavaWEB项目(springboot-mini),能满足大部分后台管理系统基础开...

Spring Boot的Security安全控制——认识SpringSecurity!

SpringBoot的Security安全控制在Web项目开发中,安全控制是非常重要的,不同的人配置不同的权限,这样的系统才安全。最常见的权限框架有Shiro和SpringSecurity。Shi...

前同事2024年接私活已入百万,都是用这几个开源的SpringBoot项目

前言不得不佩服SpringBoot的生态如此强大,今天给大家推荐几款优秀的后台管理系统,小伙伴们再也不用从头到尾撸一个项目了。SmartAdmin...

值得学习的15 个优秀开源的 Spring Boot 学习项目

SpringBoot算是目前Java领域最火的技术栈了,除了书呢?当然就是开源项目了,今天整理15个开源领域非常不错的SpringBoot项目供大家学习,参考。高富帅的路上只能帮你到这里了,...

开发企业官网就用这个基于SpringBoot的CMS系统,真香

前言推荐这个项目是因为使用手册部署手册非常...

2021年超详细的java学习路线总结—纯干货分享

本文整理了java开发的学习路线和相关的学习资源,非常适合零基础入门java的同学,希望大家在学习的时候,能够节省时间。纯干货,良心推荐!第一阶段:Java基础...

jeecg-boot学习总结及使用心得(jeecgboot简单吗)

jeecg-boot学习总结及使用心得1.jeecg-boot是一个真正前后端分离的模版项目,便于二次开发,使用的都是较流行的新技术,后端技术主要有spring-boot2.x、shiro、Myb...

后勤集团原料管理系统springboot+Layui+MybatisPlus+Shiro源代码

本项目为前几天收费帮学妹做的一个项目,JavaEEJSP项目,在工作环境中基本使用不到,但是很多学校把这个当作编程入门的项目来做,故分享出本项目供初学者参考。一、项目描述后勤集团原料管理系统spr...

白卷开源SpringBoot+Vue的前后端分离入门项目

简介白卷是一个简单的前后端分离项目,主要采用Vue.js+SpringBoot技术栈开发。除了用作入门练习,作者还希望该项目可以作为一些常见Web项目的脚手架,帮助大家简化搭建网站的流程。...

Spring Security 自动踢掉前一个登录用户,一个配置搞定

登录成功后,自动踢掉前一个登录用户,松哥第一次见到这个功能,就是在扣扣里边见到的,当时觉得挺好玩的。自己做开发后,也遇到过一模一样的需求,正好最近的SpringSecurity系列正在连载,就结...

收藏起来!这款开源在线考试系统,我爱了

大家好,我是为广大程序员兄弟操碎了心的小编,每天推荐一个小工具/源码,装满你的收藏夹,每天分享一个小技巧,让你轻松节省开发效率,实现不加班不熬夜不掉头发,是我的目标!今天小编推荐一款基于Spr...

Shiro框架:认证和授权原理(shiro权限认证流程)

优质文章,及时送达前言Shiro作为解决权限问题的常用框架,常用于解决认证、授权、加密、会话管理等场景。本文将对Shiro的认证和授权原理进行介绍:Shiro可以做什么?、Shiro是由什么组成的?举...

取消回复欢迎 发表评论: