Golang Go语言中当 P 的数量为 1 时 GMP 调度的问题
go<br>package main<br><br>import (<br> "fmt"<br> "runtime"<br> "sync"<br>)<br><br>func main() {<br> //<br> wait := sync.WaitGroup{}<br> runtime.GOMAXPROCS(1)<br> wait.Add(20)<br> str := "ABCDEFGHIJKLM"<br><br> for i := 0; i < 10; i++ {<br> go func(i int) {<br> fmt.Println(i, "---")<br> wait.Done()<br> }(i)<br> }<br><br> for i, l := 0, len(str); i < l; i++ {<br> go func(i int) {<br> fmt.Println(string(str[i]))<br> wait.Done()<br> }(i)<br> }<br> fmt.Println("---------------")<br> wait.Wait()<br>}<br><br>
为什么这个程序会优先执行下面这个 goroutine 中的最后一个,然后再回到上面去执行
输出结果如下<br>---------------<br>M<br>0 ---<br>1 ---<br>2 ---<br>3 ---<br>4 ---<br>5 ---<br>6 ---<br>7 ---<br>8 ---<br>9 ---<br>A<br>B<br>C<br>D<br>E<br>F<br>G<br>H<br>I<br>
如果从 GMP 的角度去看的话,一开始设置了 P 的数量为 1 那后续 G0 调用玩 goroutine 之后,把后续的 G 都塞到了本地 p 的队列里面 m 从里面取 输出的结果不应该是顺序的嘛, 为什么会产生单独输出一次 M 的现象
我所认为的理想状态下输出的内容<br>0123456789ABCDEFGHIM<br>
Golang Go语言中当 P 的数量为 1 时 GMP 调度的问题
更多关于Golang Go语言中当 P 的数量为 1 时 GMP 调度的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
因为 p 还有个 run_next
更多关于Golang Go语言中当 P 的数量为 1 时 GMP 调度的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
正解
每次创建 goruntine 时,都会把当前 p 的 runnext 设置为 newg
这是啥意思,进去只有一个 helloworld
我去,没想到队列 p 上面还有个 run_next, 看懂了谢谢!
在Go语言的GMP(Goroutine、M - Machine/Thread、P - Processor)模型中,当P(Processor)的数量被设置为1时,调度行为会变得相对简单但仍有其独特之处。
首先,理解GMP模型是基础:
- Goroutine(G)是Go语言中的并发体,轻量级且数量可以非常多。
- Machine/Thread(M)代表操作系统线程,执行具体的Go代码。
- Processor(P)是M和G之间的调度中介,负责将可运行的G分配到合适的M上执行。
当P的数量为1时:
-
单一调度队列:只有一个P意味着所有的可运行Goroutine都排队在这个P的调度队列中。这减少了上下文切换的复杂性,因为每次调度只需要从这一个队列中取出Goroutine。
-
M的利用:尽管只有一个P,但Go运行时仍然可以管理多个M。当P上的Goroutine都在等待I/O或其他阻塞操作时,M会被空闲出来执行其他任务或休眠,一旦P上有新的Goroutine变为可运行,M会被唤醒继续执行。
-
调度开销:由于只有一个P,调度的决策变得简单,减少了在多个P之间平衡负载的需要,从而降低了调度开销。
总的来说,当P的数量为1时,Go语言的GMP调度模型简化为单队列、多M的模式,虽然可能限制了并发的粒度,但在某些场景下(如I/O密集型应用)依然能高效运行。