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-11-15SendGrid 的 Go 客户端库怎么实现同时向多个邮箱发送邮件?-icode9专业技术文章分享
- 2024-11-15SendGrid 的 Go 客户端库怎么设置header 和 标签tag 呢?-icode9专业技术文章分享
- 2024-11-12Cargo deny安装指路
- 2024-11-02MongoDB项目实战:从入门到初级应用
- 2024-11-01随时随地一键转录,Google Cloud 新模型 Chirp 2 让语音识别更上一层楼
- 2024-10-25Google Cloud动手实验详解:如何在Cloud Run上开发无服务器应用
- 2024-10-24AI ?先驱齐聚 BAAI 2024,发布大规模语言、多模态、具身、生物计算以及 FlagOpen 2.0 等 AI 模型创新成果。
- 2024-10-20goland工具下,如修改一个项目的标准库SDK的版本-icode9专业技术文章分享
- 2024-10-17Go学习:初学者的简单教程
- 2024-10-17Go学习:新手入门完全指南