go select..case详解
1. go select是一种仅能用于channel发送和接收消息的语句,此语句运行期间是阻塞的;当 select中没有case语句的时候,会阻塞当前goroutine
2. select是go在语言层面提供的IO多路复用机制,专门用于检测多个channel是否准备完毕:可读可写
3. select语句中除default外,每个case操作一个channel,要么读要么写
4. select语句中除default外,各case的执行顺序是完全随机的
5. select中如果没有default语句,则会阻塞等待任一case
6. select语句中读操作要判断是否成功读取,关闭的channel也可以读取
实现原理:
Go在实现select时,定义了一个数据结构表示每一个case(包含default, default时一种特殊的case),select执行过程可以类比为一个函数,函数输入case数组,输出选中的case,然后程序流程转到选中的case块。
源码包src/runtime/select.go:scase
定义了表示case语句的数据结构:
1 2 3 4 5 6 7 | type scase struct { c *hchan // chan,为当前case语句操作的channel指针,一个case语句只能操作一个channel elem unsafe.Pointer // data element, 表示缓冲区地址,从channel中读除的数据或者将要写入channel的数据的存放地址 kind uint16 // 表示case的类型,非为read write default pc uintptr // race pc (for race detector / msan) releasetime int64 } |
源码包src/runtime/select.go:selectgo()
定义了select选择case的函数,伪代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | func selectgo(cas0 *scase, order0 *uint16, ncases int) (int, bool) { //1. 锁定scase语句中所有的channel //2. 按照随机顺序检测scase中的channel是否ready // 2.1 如果case可读,则读取channel中数据,解锁所有的channel,然后返回(case index, true) // 2.2 如果case可写,则将数据写入channel,解锁所有的channel,然后返回(case index, false) // 2.3 所有case都未ready,则解锁所有的channel,然后返回(default index, false) //3. 所有case都未ready,且没有default语句 // 3.1 将当前协程加入到所有channel的等待队列 // 3.2 当将协程转入阻塞,等待被唤醒 //4. 唤醒后返回channel对应的case index // 4.1 如果是读操作,解锁所有的channel,然后返回(case index, true) // 4.2 如果是写操作,解锁所有的channel,然后返回(case index, false) } |
参考文档: https://my.oschina.net/renhc/blog/2253937
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!