上卷 程序设计
中卷 标准库
- bufio 1.18
- bytes 1.18
- io 1.18
- container 1.18
- encoding 1.18
- crypto 1.18
- hash 1.18
- index 1.18
- sort 1.18
- context 1.18
- database 1.18
- connection
- query
- queryrow
- exec
- prepare
- transaction
- scan & null
- context
- tcp
- udp
- http
- server
- handler
- client
- h2、tls
- url
- rpc
- exec
- signal
- embed 1.18
- plugin 1.18
- reflect 1.18
- runtime 1.18
- KeepAlived
- ReadMemStats
- SetFinalizer
- Stack
- sync 1.18
- atomic
- mutex
- rwmutex
- waitgroup
- cond
- once
- map
- pool
- copycheck
- nocopy
- unsafe 1.18
- fmt 1.18
- log 1.18
- math 1.18
- time 1.18
- timer
下卷 运行时
源码剖析
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4.2.1 P
初始化函数最重要的事情是初始化 P 数量。
// proc.go func schedinit() { sched.maxmcount = 10000 procs := ncpu if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 { procs = n } if procresize(procs) != nil { throw("unknown runnable goroutine during bootstrap") } }
相比以前固定大小的数组,现在改用切片。
从 1.10 开始取消了 GOMAXPROCS 最大值限制。
虽然 GOMAXPROCS 默认等于 procs,但并非不能超过。
// runtime2.go var allp []*p // len(allp) == gomaxprocs; may change at safe points, otherwise immutable
数量可以更多,也可以更少。
返回有本地任务的 P 链表,在后面 StartTheWorld 时需用到。
// proc.go // Change number of processors. The world is stopped, sched is locked. // Returns list of Ps with local work, they need to be scheduled by the caller. func procresize(nprocs int32) *p { old := gomaxprocs // 如果 allp 容量不足,扩容。 if nprocs > int32(len(allp)) { if nprocs <= int32(cap(allp)) { allp = allp[:nprocs] } else { nallp := make([]*p, nprocs) copy(nallp, allp[:cap(allp)]) allp = nallp } } // 初始化新 P。(切片 allp 只是存储位置,并没初始化) for i := old; i < nprocs; i++ { pp := allp[i] if pp == nil { pp = new(p) } // 初始化 P.cache 等属性。 pp.init(i) atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp)) } // 通过 id 检查当前 P 是否在调整范围,或重新绑定。 _g_ := getg() if _g_.m.p != 0 && _g_.m.p.ptr().id < nprocs { // 继续使用。 _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) } // 缩减 P 数量,释放多余的。 for i := nprocs; i < old; i++ { p := allp[i] // 清除关联资源(任务放回全局队列)。 p.destroy() } // 调整 allp. if int32(len(allp)) != nprocs { allp = allp[:nprocs] } var runnablePs *p for i := nprocs - 1; i >= 0; i-- { p := allp[i] // 跳过当前 P。 if _g_.m.p.ptr() == p { continue } // 将有本地任务的 P 构成链表,用于返回。 p.status = _Pidle if runqempty(p) { pidleput(p) } else { p.m.set(mget()) p.link.set(runnablePs) runnablePs = p } } 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 }
// proc.go func (pp *p) init(id int32) { pp.id = id pp.mcache = allocmcache() }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论