Golang源码学习:调度逻辑(一)初始化 (2)

mcommoninit基本上就是做一些m0的初始化。

schedinit->procresize // 传入参数nprocs为期望的所有p的个数 func procresize(nprocs int32) *p { old := gomaxprocs // gomaxprocs在本方法的末尾会被更改 if old < 0 || nprocs <= 0 { throw("procresize: invalid arg") } if trace.enabled { traceGomaxprocs(nprocs) } // 更新统计信息 now := nanotime() if sched.procresizetime != 0 { sched.totaltime += int64(old) * (now - sched.procresizetime) } sched.procresizetime = now // 初始化allp if nprocs > int32(len(allp)) { // Synchronize with retake, which could be running // concurrently since it doesn't run on a P. lock(&allpLock) if nprocs <= int32(cap(allp)) { allp = allp[:nprocs] } else { // 初始化一个临时变量nallp,与现存的allp合并,然后将nallp赋值给全局变量allp nallp := make([]*p, nprocs) copy(nallp, allp[:cap(allp)]) allp = nallp } unlock(&allpLock) } // 初始化新添加到allp中的元素 for i := old; i < nprocs; i++ { pp := allp[i] if pp == nil { pp = new(p) } pp.init(i) // 会初始化p结构的属性:id,status,mcache等 atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp)) // 赋值 } _g_ := getg() // 初始化的时候 _g_.m.p = 0 所以走else if _g_.m.p != 0 && _g_.m.p.ptr().id < nprocs { // continue to use the current P _g_.m.p.ptr().status = _Prunning _g_.m.p.ptr().mcache.prepareForSweep() } else { // 此处省略一些初始化时不会进入的代码 _g_.m.p = 0 _g_.m.mcache = nil p := allp[0] p.m = 0 p.status = _Pidle acquirep(p) // m.mcache = p.mcache;p和m相互绑定;p.status = _Prunning。下面有分析。 if trace.enabled { traceGoStart() } } // 释放未使用的p的资源,比如调用runtime.GOMAXPROCS(num),会调用procresize。 // num小于当前p的数量时,会执行此处 for i := nprocs; i < old; i++ { p := allp[i] p.destroy() // can't free P itself because it can be referenced by an M in syscall } // Trim allp. if int32(len(allp)) != nprocs { lock(&allpLock) allp = allp[:nprocs] unlock(&allpLock) } // 将除了当前m绑定p的其余allp中的都以链表形式存入sched.pidle中 var runnablePs *p for i := nprocs - 1; i >= 0; i-- { p := allp[i] if _g_.m.p.ptr() == p { // 是否是当前g.m的p continue } p.status = _Pidle if runqempty(p) { pidleput(p) // 将p放入到空闲列表中 } else { p.m.set(mget()) p.link.set(runnablePs) runnablePs = p } } // 这里会更改gomaxprocs的值 stealOrder.reset(uint32(nprocs)) var int32p *int32 = &gomaxprocs // make compiler check that gomaxprocs is an int32 atomic.Store((*uint32)(unsafe.Pointer(int32p)), uint32(nprocs)) return runnablePs }

总结一下procresize的工作:

allp切片中p的数量小于期望p数量时,对allp进行扩容

使用new创建p并调用p.init初始化刚扩容出的,init中为p分配id和mcache

初始化时,调用acquirep使allp[0]与m0相互绑定,并且m.mcache = p.mcache,p.status = _Prunning

allp切片中p的数量大于期望p数量时,调用p.destroy释放未使用的p的资源

将除了allp[0]之外的p状态设置为_Pidle并加入到全局空闲列表sched.pidle中

更改gomaxprocs值为nprocs

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zgwswf.html