当显式调用更多的工作线程时,gomaxprocs将被忽略。

huangapple go评论70阅读模式
英文:

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 (
	&quot;fmt&quot;
	&quot;runtime&quot;
	&quot;sync&quot;
	&quot;time&quot;
)

func worker(i int, waiter chan struct{}, wg *sync.WaitGroup) {
	defer func(waiter chan struct{}, wg *sync.WaitGroup) {
		fmt.Printf(&quot;worker %d done\n&quot;, i)
		wg.Done()
		&lt;-waiter

	}(waiter, wg)
	fmt.Printf(&quot;worker %d starting\n&quot;, 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 &lt; items; i++ {
		wg.Add(1)
		waiter &lt;- struct{}{}
		go worker(i, waiter, &amp;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.

huangapple
  • 本文由 发表于 2021年10月9日 16:41:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/69505101.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定