006-Golang1.17源码分析之select
2022/2/21 20:35:46
本文主要是介绍006-Golang1.17源码分析之select,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
Golang1.17源码分析之select-006
Golang1.17 学习笔记006
源码地址:runtime/select.go
数据结构:
type scase struct { c *hchan // chan elem unsafe.Pointer // data element }
核心函数:selectgo()
order0 为一个两倍 cas0 数组长度的 buffer,保存 scase 随机序列 pollorder 和 scase 中 channel 地址序列 lockorder
pollorder:每次selectgo执行都会把scase序列打乱,以达到随机检测case的目的
lockorder:所有case语句中channel序列,以达到去重防止对channel加锁时重复加锁的目的
func selectgo(cas0 *scase, order0 *uint16, pc0 *uintptr, nsends, nrecvs int, block bool) (int, bool) { // generate permuted order norder := 0 for i := range scases { cas := &scases[i] // Omit cases without channels from the poll and lock orders. if cas.c == nil { cas.elem = nil // allow GC continue } // .... i++ } pollorder = pollorder[:norder] lockorder = lockorder // sort the cases by Hchan address to get the locking order. // simple heap sort, to guarantee n log n time and constant stack footprint. // 一系列堆排序操作 // lock all the channels involved in the select sellock(scases, lockorder) // pass 1 - look for something already waiting for _, casei := range pollorder { } if !block { selunlock(scases, lockorder) casi = -1 goto retc } // pass 2 - enqueue on all chans gp = getg() if gp.waiting != nil { throw("gp.waiting != nil") } nextp = &gp.waiting for _, casei := range lockorder { } // wait for someone to wake us up gp.param = nil // Signal to anyone trying to shrink our stack that we're about // to park on a channel. The window between when this G's status // changes and when we set gp.activeStackChans is not safe for // stack shrinking. gopark(selparkcommit, nil, waitReasonSelect, traceEvGoBlockSelect, 1) sellock(scases, lockorder) // pass 3 - dequeue from unsuccessful chans otherwise they stack up on quiet channels // record the successful case, if any. We singly-linked up the SudoGs in lock order. // Clear all elem before unlinking from gp.waiting. for sg1 := gp.waiting; sg1 != nil; sg1 = sg1.waitlink { sg1.isSelect = false sg1.elem = nil sg1.c = nil } gp.waiting = nil for _, casei := range lockorder { } } // 伪代码 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) }
总结
-
select语句中除default外,各case执行顺序是随机的
-
select语句中如果没有default语句,则会阻塞等待任一case
参考文献:《Go专家编程》之 select
这篇关于006-Golang1.17源码分析之select的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-12-24MongoDB资料:新手入门完全指南
- 2024-12-20go-zero 框架的 RPC 服务 启动start和停止 底层是怎么实现的?-icode9专业技术文章分享
- 2024-12-19Go-Zero 框架的 RPC 服务启动和停止的基本机制和过程是怎么实现的?-icode9专业技术文章分享
- 2024-12-18怎么在golang中使用gRPC测试mock数据?-icode9专业技术文章分享
- 2024-12-15掌握PageRank算法核心!你离Google优化高手只差一步!
- 2024-12-15GORM 中的标签 gorm:"index"是什么?-icode9专业技术文章分享
- 2024-12-11怎么在 Go 语言中获取 Open vSwitch (OVS) 的桥接信息(Bridge)?-icode9专业技术文章分享
- 2024-12-11怎么用Go 语言的库来与 Open vSwitch 进行交互?-icode9专业技术文章分享
- 2024-12-11怎么在 go-zero 项目中发送阿里云短信?-icode9专业技术文章分享
- 2024-12-11怎么使用阿里云 Go SDK (alibaba-cloud-sdk-go) 发送短信?-icode9专业技术文章分享