(1)pin 方法内部通过 native 方法 runtime_procPin 取出当前 P 的 index,并且将当前 goroutine 与 P 进行绑定,短暂处于不可抢占状态; (2)如果是首次调用 pin 方法,则会走进 pinSlow 方法; (3)在pinSlow 方法中,会完成 Pool.local 的初始化,并且将当前 Pool 添加到全局的 allPool 数组中,用于 gc 回收;...
所以不能被抢占也不会被调度(普通G也可以执行runtime_procPin禁止抢占),G0的栈是系统分配的,比普通...
必须与runtime_procUnpin搭配使用 该函数Put和Get均会调用 func (p *Pool) pin() (*poolLocal, int) { // 与runtime_procUnpin搭配使用 pid := runtime_procPin() // In pinSlow we store to local and then to localSize, here we load in opposite order. // Since we've disabled preemption, ...
return p.pinSlow() } 1. 2. 3. 4. 5. 6. 7. 8. 9. • pin 方法内部通过 native 方法 runtime_procPin 取出当前 P 的 index,并且将当前 goroutine 与 P 进行绑定,短暂处于不可抢占状态; • 如果是首次调用 pin 方法,则会走进 pinSlow 方法; • 在pinSlow 方法中,会完成 Pool.local 的...
func(p *Pool)pinSlow() (*poolLocal,int) {// 调用pinSlow前, 必定调用了pin, 暂时释放, 因为在pin的过程中, 无法对互斥锁进行操作runtime_procUnpin()// 初始化local, 禁止并发访问allPoolsMu.Lock()deferallPoolsMu.Unlock()// 重新pinpid := runtime_procPin()// poolCleanup 在pin的过程中, GC...
runtime_procUnpin() ifrace.Enabled { race.Enable() } } 所以我们看到 Put 的操作很简单,就是单纯地放回 Pool 中,涉及到不同的存放位置。基本上可以总结为下面的操作流程: 1、首先调用 p.pin() 抢占p,获取 localpool 2、优先放归还到private中 ...
runtime_procUnpin() allPoolsMu.Lock() defer allPoolsMu.Unlock() pid := runtime_procPin() // poolCleanup won't be called while we are pinned. // 再次检查是否LocalPool是否有对应的索引,避免其他的线程造成影响 s := p.localSize l := p.local ...
func(p*Pool)Get()interface{}{...l,pid:=p.pin()x:=l.private l.private=nilifx==nil{// Try to pop the head of the local shard. We prefer// the head over the tail for temporal locality of// reuse.x,_=l.shared.popHead()ifx==nil{x=p.getSlow(pid)}}runtime_procUnpin()......
一旦当前 Goroutine 能够进入自旋就会调用runtime_doSpin,它最终调用汇编语言编写的方法procyield并执行指定次数的PAUSE指令,PAUSE指令什么都不会做,但是会消耗 CPU 时间,每次自旋都会调用30次PAUSE,下面是该方法在 386 架构的机器上的实现: 代码语言:javascript ...
2. 第二种就是持有锁的那个 goroutine 了,可以搜下 pinSlow 所有的 gouroutine ,是否有不同于 allPoolsMu.Lock() 的。再顺着这个 goroutine ,看它为什么卡住func (p *Pool) pinSlow() (*poolLocal, int) { // Retry under the mutex. // Can not lock the mutex while pinned. runtime_procUnpin...