上卷 程序设计
中卷 标准库
- 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
下卷 运行时
源码剖析
- 1. 初始化
- 2. 内存分配
- 3. 垃圾回收
- 4. 并发调度
- 5. 通道
- 6. 延迟调用
- 7. 终结器
- 8. 其他
附录
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
4.2.1 P
调度器初始化函数最重要的事情是初始化 P 数量。
// proc.go func schedinit() { procs := ncpu if n, ok := atoi32(gogetenv("GOMAXPROCS")); ok && n > 0 { procs = n } if procresize(procs) != nil { throw("unknown runnable goroutine during bootstrap") } }
调整 P 数量会导致 STW。
// runtime2.go // len(allp) == gomaxprocs; may change at safe points, otherwise // immutable. var allp []*p
// Change number of processors. // Returns list of Ps with local work, they need to be scheduled by the caller. func procresize(nprocs int32) *p { // !!!! assertWorldStopped() // 当前值。 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。 for i := old; i < nprocs; i++ { pp := allp[i] if pp == nil { pp = new(p) } pp.init(i) atomicstorep(unsafe.Pointer(&allp[i]), unsafe.Pointer(pp)) } // 检查当前 P 是否在裁剪范围。(nprocs < old) _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 { // 在裁剪范围,解除当前绑定。 if _g_.m.p != 0 { _g_.m.p.ptr().m = 0 } _g_.m.p = 0 // 重新绑定 allp[0]。 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 } } return runnablePs }
初始化和释放操作,会对相关绑定资源进行处理。
func (pp *p) init(id int32) { pp.id = id pp.status = _Pgcstop pp.sudogcache = pp.sudogbuf[:0] pp.deferpool = pp.deferpoolbuf[:0] pp.wbBuf.reset() if pp.mcache == nil { if id == 0 { pp.mcache = mcache0 } else { pp.mcache = allocmcache() } } }
func (pp *p) destroy() { // !!! assertWorldStopped() // 将本地队列的任务转移到全局队列。 for pp.runqhead != pp.runqtail { pp.runqtail-- gp := pp.runq[pp.runqtail%uint32(len(pp.runq))].ptr() globrunqputhead(gp) } if pp.runnext != 0 { globrunqputhead(pp.runnext.ptr()) pp.runnext = 0 } // 停止并转移其他相关资源 ... if len(pp.timers) > 0 { plocal := getg().m.p.ptr() moveTimers(plocal, pp.timers) pp.timers = nil pp.numTimers = 0 pp.deletedTimers = 0 atomic.Store64(&pp.timer0When, 0) } if gcphase != _GCoff { wbBufFlush1(pp) pp.gcw.dispose() } for i := range pp.sudogbuf { pp.sudogbuf[i] = nil } pp.sudogcache = pp.sudogbuf[:0] for j := range pp.deferpoolbuf { pp.deferpoolbuf[j] = nil } pp.deferpool = pp.deferpoolbuf[:0] systemstack(func() { for i := 0; i < pp.mspancache.len; i++ { mheap_.spanalloc.free(unsafe.Pointer(pp.mspancache.buf[i])) } pp.mspancache.len = 0 pp.pcache.flush(&mheap_.pages) }) freemcache(pp.mcache) pp.mcache = nil gfpurge(pp) traceProcFree(pp) // 重置状态。 pp.gcAssistTime = 0 pp.status = _Pdead }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论