英文:
gomaxprocs ignored when more workers are explicityl called
问题
如何使用gomaxprocs?下面的代码设置了gomaxprocs,但是生成了比设置的更多的工作进程。我期望有2个进程,但实际上有5个在运行。
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func worker(i int, waiter chan struct{}, wg *sync.WaitGroup) {
defer func(waiter chan struct{}, wg *sync.WaitGroup) {
fmt.Printf("worker %d done\n", i)
wg.Done()
<-waiter
}(waiter, wg)
fmt.Printf("worker %d starting\n", i)
time.Sleep(time.Second)
}
func main() {
runtime.GOMAXPROCS(2)
var concurrency = 5
var items = 10
waiter := make(chan struct{}, concurrency)
var wg sync.WaitGroup
for i := 0; i < items; i++ {
wg.Add(1)
waiter <- struct{}{}
go worker(i, waiter, &wg)
}
wg.Wait()
}
你可以使用runtime.GOMAXPROCS(n)
来设置goroutine并发执行的最大CPU数。在你的代码中,runtime.GOMAXPROCS(2)
将最大CPU数设置为2。然而,你的代码中使用了一个带有缓冲通道的waiter
来控制并发执行的goroutine数量。这意味着在waiter
通道已满之前,你可以生成更多的goroutine。因此,尽管你设置了最大CPU数为2,但仍然会生成更多的goroutine并运行。
要解决这个问题,你可以将waiter
通道的缓冲大小设置为最大CPU数,以限制并发执行的goroutine数量。例如,将concurrency
变量设置为2:
var concurrency = 2
然后,将waiter
通道的缓冲大小设置为concurrency
:
waiter := make(chan struct{}, concurrency)
这样,当waiter
通道已满时,将不会生成更多的goroutine,从而限制并发执行的goroutine数量与最大CPU数相匹配。
英文:
How can i use gomaxprocs? The code below sets gomaxprocs, but then more workers are spawned that set. I expect 2 processes but 5 are still run.
package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func worker(i int, waiter chan struct{}, wg *sync.WaitGroup) {
defer func(waiter chan struct{}, wg *sync.WaitGroup) {
fmt.Printf("worker %d done\n", i)
wg.Done()
<-waiter
}(waiter, wg)
fmt.Printf("worker %d starting\n", i)
time.Sleep(time.Second)
}
func main() {
runtime.GOMAXPROCS(2)
var concurrency = 5
var items = 10
waiter := make(chan struct{}, concurrency)
var wg sync.WaitGroup
for i := 0; i < items; i++ {
wg.Add(1)
waiter <- struct{}{}
go worker(i, waiter, &wg)
}
wg.Wait()
}
答案1
得分: 3
Go有三个概念,对于C/C++程序员来说,它们相当于线程:G、P、M。
- M = 实际的线程
- G = Goroutines(即程序中的代码)
- P = 处理器
Go没有用于限制M数量的API。也没有用于限制G数量的API - 每次调用go func(...)
都会创建一个新的G。GOMAXPROCS
用于限制P的数量。
每个P用于跟踪某个正在运行的Goroutine的运行时状态。
你应该将GOMAXPROCS
视为用于运行Goroutines的最大M数量。 (还有其他的M不运行Goroutines,而是处理垃圾回收任务,并作为创建新M的模板线程等。一些M用于保存运行时状态,而一些Go代码在系统调用中被阻塞。)
因此,就你的程序中的代码而言,GOMAXPROCS
是限制其Go代码执行并行性的约束。当一个正在运行的Goroutine达到被阻塞的点时,它会被“停放”,并且它的P会被用来恢复执行其他未被阻塞的Goroutine。
英文:
Go has three concepts for what C/C++ programmers think of as a thread: G, P, M.
- M = actual thread
- G = Goroutines (i.e., the code in your program)
- P = Processor
There is no Go API for limiting the number of Ms. There is no API for limiting the number of Gs - a new one gets created every time go func(...)
is called. The GOMAXPROCS
thing is there to limit Ps.
Each P is used to track the runtime state of some running Goroutine.
You should think of GOMAXPROCS
as the peak number of Ms devoted to running Goroutines. (There are other Ms that don't run Goroutines, but handle garbage collection tasks and serve as template threads for creating new Ms as needed etc. Some Ms are devoted to holding runtime state while some Go code is blocked inside a system call.)
So, in terms of the code in your program, GOMAXPROCS
is a constraint for how parallel its Go code execution can be. When a running Goroutine reaches a point where it becomes blocked, it is parked and its P is used to resume execution of some other Goroutine that is not blocked.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论