当前位置: 首页 > news >正文

Go语言select

select是什么

   select是Go语言层面提供的一种多路复用机制,用于检测当前goroutine连接的多个channel是否有数据准备完毕,可用于读或写。

        Go语言的select语句,是用来起一个goroutine监听多个Channel的读写事件,提高从多个Channel获取信息的效率,相当于是单线程处理多个IO事件,其思想基本相同。

select的用法

select的基本使用模式如下:

select {case <- channel1:     // 如果从channel1读取数据成功,执行case语句 do ...   case channel2 <- 1:   // 如果向channel2写入数据成功,执行case语句 do ...          default:              // 如果上面都没有成功,进入default处理流程do ...
}

        可以看到,select的用法形式类似于switch,但是区别于switch的是select各个case的表达式必须都是channel的读写操作select通过多个case语句监听多个channel的读写操作是否准备好可以执行,其中任何一个case可以执行了则选择该case语句执行,如果没有可以执行的case,则执行default语句,如果没有default,则当前goroutine会阻塞。 

空select永久阻塞

当一个select中什么语句都没有,没有任何case,将会永久阻塞:

package mainfunc main() {select {}
}

运行结果:

fatal error: all goroutines are asleep - deadlock!

        程序因为select语句导致永久阻塞,当前goroutine阻塞之后,由于Go语言自带死锁检测机制,发现当前goroutine永远不会被唤醒,会报上述死锁错误。 

没有default且case无法执行的select永久阻塞

看下面示例:

package mainimport ("fmt"
)func main() {ch1 := make(chan int, 1)ch2 := make(chan int, 1)select {case <-ch1:fmt.Printf("received from ch1")case num := <-ch2:fmt.Printf("num is: %d", num)}
}

运行结果:

fatal error: all goroutines are asleep - deadlock!

        程序中 select从两个channelch1ch2中读取数据,但是两个channel都没有数据,且没有goroutine往里面写数据,所以不可能读到数据,这两个case永远无法执行到,select也没有default,所以会出现永久阻塞,报死锁。 

单一case和default的select

package mainimport ("fmt"
)func main() {ch := make(chan int, 1)select {case <-ch:fmt.Println("received from ch")default:fmt.Println("default!!!")}
}

运行结果:

default!!!

        执行到select语句的时候,由于ch中没有数据,且没有goroutinechannel中写数据,所以case不可能执行到,就会执行default语句,打印出default!!!。 

 多个case和default的select

package mainimport ("fmt""time"
)func main() {ch1 := make(chan int, 1)ch2 := make(chan int, 1)go func() {time.Sleep(time.Second)for i := 0; i < 3; i++ {select {case v := <-ch1:fmt.Printf("Received from ch1, val = %d\n", v)case v := <-ch2:fmt.Printf("Received from ch2, val = %d\n", v)default:fmt.Println("default!!!")}time.Sleep(time.Second)}}()ch1 <- 1time.Sleep(time.Second)ch2 <- 2time.Sleep(4 * time.Second)
}

运行结果:

Received from ch1, val = 1
Received from ch2, val = 2
default!!!

        主goroutine中向后往管道ch1ch2中发送数据,在子goroutine中执行两个select,可以看到,在执行select的时候,那个case准备好了就会执行当下case的语句,最后没有数据可接受了,没有case可以执行,则执行default语句。

注意当多个case都准备好了的时候,会随机选择一个执行

package mainimport ("fmt"
)func main() {ch1 := make(chan int, 1)ch2 := make(chan int, 1)ch1 <- 5ch2 <- 6select {case v := <-ch1:fmt.Printf("Received from ch1, val = %d\n", v)case v := <-ch2:fmt.Printf("Received from ch2, val = %d\n", v)default:fmt.Println("default!!!")}
}

运行结果:

Received from ch2, val = 6

多次执行,2个case都有可能打印,这就是select选择的随机性。

http://www.xdnf.cn/news/1241335.html

相关文章:

  • 开源的现代数据探索和可视化平台:Apache Superset 使用 Docker Compose
  • 笔记本电脑联想T14重启后无法识别外置红米屏幕
  • 如何手动打包 Linux(麒麟系统)的 Qt 程序
  • JVM学习专题(四)对象创建过程
  • 【Spring Boot 】Spring Boot + OpenAI API 万能集成模板,实现快速集成AI
  • sqli-labs通关笔记-第30关GET字符注入(WAF绕过 双引号闭合 手工注入+脚本注入两种方法)
  • AI Agents漏洞百出,恶意提示等安全缺陷令人担忧
  • 高防服务器租用的作用都有哪些?
  • 随笔之 ClickHouse 列式分析数据库安装注意事项及基准测试
  • 【BUUCTF系列】[SUCTF 2019]EasySQL1
  • 【论文简读】LongSplat
  • Claude Code深度操作指南:从零到专家的AI编程助手实战
  • MAC-Spring Cloud + Spring Boot + RocketMQ集成
  • 链表问题解决分析框架
  • SP20D120CTU:1200 V/20 A SiC肖特基二极管的TO-263封装升级版,数据工程师必看!
  • 政府财政行业云原生转型之路
  • Maya 2024安装指南及安装包下载
  • 车载通信架构 ---车内通信的汽车网络安全
  • Linux中netstat详细使用指南
  • 【Linux】System V - 基于建造者模式的信号量
  • DP-v2.1-mem-clean学习(3.6.8.2-3.6.8.3)
  • Linux文件权限管理与ACL配置指南
  • wpf Image 转 90 度
  • 9.感知机、神经网络
  • 国产化Word处理控件Spire.Doc教程:Python提取Word文档中的文本、图片、表格等
  • Excel商业智能分析报表 【销售管理分析仪】
  • 百度翻译详解:包括PaddleNLP、百度AI开放平台、接口逆向(包括完整代码)
  • Android工程命令行打包并自动生成签名Apk
  • Go语言高并发价格监控系统设计
  • 向量空间模型