返回介绍

上卷 程序设计

中卷 标准库

下卷 运行时

源码剖析

附录

4.2.1 P

发布于 2024-10-12 19:16:05 字数 2899 浏览 0 评论 0 收藏 0

初始化函数最重要的事情是初始化 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文