Golang线程计数误导

3
我用Go写了一个小应用程序,启动了4个线程来完成各种任务 + 一个主线程。所以总共有5个线程。但是如果我启动活动监视器并监视进程,我看到的是这样的:
首先为什么会有7个线程?而且它不是恒定的。有时候是5,有时候是7。此外,所有由主线程启动的4个线程在完成他们应该做的事情后都会结束。我通过在线程顶部放置一个不同的语句来验证线程的结束。然而,在活动监视器中,线程计数保持为7。
有人知道这里发生了什么吗?这些额外的线程是由Go运行时启动的吗?有没有办法找出由我的代码而不是Go运行时启动的活动程序中有多少线程是活动的。
3个回答

8

是的,它们由运行时启动,例如http://play.golang.org/p/c0cIngo_sO将打印正在运行的4个goroutine。

Goroutine不是线程,1个操作系统线程可以处理数百个goroutine,但如果您正在执行某些重型操作或使用阻塞式系统调用,则运行时将启动一个新线程来处理其他goroutine。


因此,Go运行时将在需要时启动新的操作系统线程并将goroutine移动到该线程上。如果需要,我不需要调用GOMAXPROCS来使运行时生成新线程。 - nik
据我所知,GOMAXPROCS将操作系统线程分配给物理处理器,因此这仍然是一个好主意,否则所有的goroutine可能会在一个处理器核心上运行。 - OneOfOne
1
在网上阅读时,我发现了这个内容:“运行时开始有几个G。其中一个负责垃圾回收,另一个负责调度,还有一个代表用户的Go代码。最初,创建一个M来启动运行时。随着程序的进展,用户的Go程序可能会创建更多的G,并且可能需要更多的M来运行所有的G。随着这种情况的发生,运行时可以根据需要提供额外的线程,直到达到GOMAXPROCS。因此,在任何给定时间,最多只有GOMAXPROCS个活动M。”因此,如果需要,操作系统线程将自行创建。 - nik

3

当你说线程时,我想你是指 Goroutines。

Go 运行时会将轻量级的 Goroutines 透明地复用到操作系统线程上。这也是为什么你不需要调用像 select() 这样的函数——这是运行时的工作。

如果你生成了 7 个 Goroutines,并且其中一些被阻塞,运行时可能会决定终止空闲的操作系统线程。这就是为什么你看到的线程数比 Goroutines 少的原因。


1
我认为你把Goroutines和线程混淆了。
在您的Go程序中,您所指的线程实际上是goroutine,它是一种协程而不是真正的线程,由go的运行时实现(您需要了解go运行时,每个go程序都在运行时上运行,运行时实际上使用线程来实现goroutine)。不同的goroutine可以在同一个线程中运行,也可能不是,但你永远不会知道。您可以使用runtime.GOMAXPROCS来进行多核CPU操作。
而您在监视器中看到的线程是真正的线程。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接