【问题标题】:Golang: why runtime.GOMAXPROCS is limited to 256?Golang:为什么 runtime.GOMAXPROCS 限制为 256?
【发布时间】:2017-09-29 05:10:52
【问题描述】:

我在 MacBook 和 Ubuntu 上玩 golang 1.7.3,发现 runtime.GOMAXPROCS 限制为 256。有谁知道这个限制来自哪里?这是否记录在任何地方,为什么会有限制?这是实现优化吗?

我只能在描述 golang 运行时包的页面上找到 256 的引用:https://golang.org/pkg/runtime/。 runtime.MemStats 结构有几个大小为 256 的 stat 数组:

type MemStats struct {
    ...
    PauseNs       [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256]
    PauseEnd      [256]uint64 // circular buffer of recent GC pause end times

这是我使用的示例 golang 代码:

func main() {
    runtime.GOMAXPROCS(1000)
log.Printf("GOMAXPROCS %d\n", runtime.GOMAXPROCS(-1))

}

打印 GOMAXPROCS 256

附: 另外,有人可以向我指出有关此 GOMAXPROCS 如何与 golang 调度程序使用的操作系统线程数相关的文档(如果有的话)。我们要观察运行 GOMAXPROCS OS 线程的 go 编译代码吗?

编辑:感谢@twotwotwo 指出 GOMAXPROCS 与操作系统线程的关系。仍然有趣的是,文档没有提到这个 256 限制(其他在 MemStats 结构中可能相关也可能不相关)。

我想知道是否有人知道这个 256 数字的真正原因。

【问题讨论】:

  • "GOMAXPROCS变量限制了可以同时执行用户级Go代码的操作系统线程数。代表Go代码在系统调用中可以阻塞的线程数没有限制; 这些不计入 GOMAXPROCS 限制。此包的 GOMAXPROCS 函数查询并更改限制。来自运行时文档。在答案中多写一点。

标签: go


【解决方案1】:

package runtime docs 阐明了 GOMAXPROCS 与操作系统线程的关系:

GOMAXPROCS 变量限制了可以同时执行用户级 Go 代码的操作系统线程数。代表 Go 代码在系统调用中可以阻塞的线程数没有限制;这些不计入 GOMAXPROCS 限制。此包的 GOMAXPROCS 函数查询和更改限制。

因此,您可以看到更多的 GOMAXPROCS 操作系统线程(因为有些在系统调用中被阻塞,并且数量没有限制)或更少(因为 GOMAXPROCS 仅记录到限制的数量线程,而不是确切地规定它)。

我认为封顶 GOMAXPROCS 符合该文档的精神——您指定您可以使用 1000 个操作系统线程运行 Go 代码,但运行时决定“仅”运行 256 个。这并不限制 goroutines 是活跃的,因为它们被多路复用到 OS 线程上——当一个 goroutine 阻塞(例如,等待网络读取完成)时,Go 的内部调度程序在同一个 OS 线程上启动其他工作。

Go 团队可能会做出这样的选择,以尽量减少 Go 程序最终运行的操作系统线程数是当今大多数机器的内核数倍的可能性;这将导致更多的操作系统上下文切换,这可能比用户模式 ​​goroutine 切换慢,如果 GOMAXPROCS 保持在 CPU 内核的数量。或者,设计 Go 的内部调度程序在 GOMAXPROCS 上有一个上限可能会很方便。

Goroutines vs Threads 并不完美,例如goroutines 现在没有分段堆栈,但它可以帮助您了解这里发生了什么。

【讨论】:

    【解决方案2】:

    请注意,从下一个 Go 1.10(2018 年第一季度)开始,GOMAXPROCS 将受到...的限制。

    运行时不再人为限制GOMAXPROCS(之前限制为1024)。

    查看Austin Clements (aclements)commit ee55000,它修复了issue 15131

    现在allp 是动态分配的,不需要硬性上限 在GOMAXPROCS


    allp is defined here.

    另见commit e900e27

    runtime:清理allp 上的循环

    allp 现在的长度为 gomaxprocs,这意味着没有一个 allp[i] 为 nil 或处于状态 _Pdead
    这让我们可以用正常范围循环替换 allp 上的几种不同样式的循环。

    for i := 0; i < gomaxprocs; i++ { ... } 循环可以简单地覆盖 allp.
    同样,range loops over allp[:gomaxprocs] 的范围可以超过 allp.

    检查p == nil || p.state == _Pdead 的循环不需要检查 这个不要了。

    检查p == nil 的循环不必检查这个if dead Ps 不要影响他们。我检查了所有这样的循环实际上是 不受死 Ps 的影响。一个循环可能受到影响,这 通过在procresize 中清零p.gcAssistTime 来修复。

    【讨论】:

      猜你喜欢
      • 2013-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-09
      • 2019-02-11
      • 2014-11-29
      • 1970-01-01
      相关资源
      最近更新 更多