【问题标题】:Number of threads used by Go runtimeGo 运行时使用的线程数
【发布时间】:2025-12-11 21:55:01
【问题描述】:

Go 运行时(调度程序、垃圾收集器等)可以使用多少个线程?例如,如果GOMAXPROCS10,那么运行时将使用多少个内核线程?

编辑:

我正在阅读 the rationale 在 Go 1.5 中将 GOMAXPROCS 更改为 runtime.NumCPU()。曾经有一句话声称“单goroutine程序的性能可以通过提高GOMAXPROCS来提高,因为运行时的并行性,尤其是垃圾收集器。”

我真正的问题是:如果我有一个在具有 CPU 配额的 Docker 容器中运行的单协程程序,我需要多少逻辑处理器才能获得最大性能?

【问题讨论】:

  • 我认为答案是:没有。因为例如GC 不在线程上运行,而是在 goroutine 上运行。最多会有 10 个非阻塞线程,所有的 goroutine 都调度在这 10 个(非阻塞)线程上。您的用户代码 goroutine 以及例如由垃圾收集器创建的 goroutine。

标签: multithreading go docker concurrency goroutine


【解决方案1】:

没有直接的相关性。您的应用使用的线程数可能少于、等于或多于 10 个。

引用runtime的包文档:

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

因此,如果您的应用程序没有启动任何新的 goroutine,线程数将少于 10。

如果您的应用启动了许多 goroutine (>10),其中没有一个是阻塞的(例如在系统调用中),那么 10 个操作系统线程将同时执行您的 goroutine。

如果您的应用启动许多 goroutine,其中许多 (>10) 在系统调用中被阻塞,则会产生超过 10 个操作系统线程(但最多只有 10 个会执行用户级 Go 代码)。

有关示例和详细信息,请参阅此问题:Why does it not create many threads when many goroutines are blocked in writing file in golang?

编辑(响应您的编辑):

我相信GOMAXPROCS 的默认值是逻辑 CPU 的数量,原因是:因为通常它提供了最高的性能。你可以把它留在那里。一般来说,如果你只有 1 个 goroutine,并且你确定你的代码不会产生更多,GOMAXPROCS=1 就足够了,但你应该测试并且不要接受任何字眼。

【讨论】:

  • 感谢您的回答!我对我的问题进行了编辑。
  • If your app starts many goroutines where many (>10) are blocked in system calls, more than 10 OS threads will be spawned (but only at most 10 will be executing user-level Go code). 这是否意味着如果我的代码执行大量 IO(比如 1000 次),我可能有 1000 次线程?在这种情况下,我的代码是否会遇到 outOfMemory 之类的问题,无法像其他语言那样产生更多线程?
  • @AbhishekArya 是的,但是执行数千个并发 IO 操作是一个糟糕的设计。使用工作池高效地执行并发操作。