0%

goroutine调度器

goroutine调度器简介

G-P-M模型,下面这张图很直观。

具体内容,参考以下链接,已经说得很详细,不再重复。

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package main
import "fmt"
import "time"
import "runtime"

func main() {
var x int
fmt.Println("GOMAXPROCS =", runtime.GOMAXPROCS(0) )
threads := runtime.GOMAXPROCS(0)
for i := 0; i < threads; i++ {
go func() {
for { x++ }
}()
}
fmt.Println("Before time.Sleep")
time.Sleep(time.Second)
fmt.Println("After time.Sleep")
fmt.Println("x =", x) //程序能运行到这里吗?
}

运行之后,发现main函数运行到Sleep之后,就卡住了,是什么原因呢?

1
2
3
4
5
[patrickxu@vm1 src]$ ./test
GOMAXPROCS = 8
Before time.Sleep


因为main函数在执行time.Sleep(time.Second)后,main函数本身占据的P(G-P-M模型中的P)也被for{ x++ }一直占着,抢占的机制。这下总共8个P,全部一直被for { x++ }占着,永远轮不到主函数了。

runtime.GOMAXPROCS(0)默认等于CPU核数8。每个P可以分配到一个M(即线程),总共2 + runtime.GOMAXPROCS(0) = 10个。

1
2
3
4
5
6
7
8
9
10
11
[patrickxu@vm1 ~]$ ps -eLf | grep test
519 26778 26325 26778 0 10 00:18 pts/42 00:00:00 ./test
519 26778 26325 26779 0 10 00:18 pts/42 00:00:00 ./test
519 26778 26325 26780 99 10 00:18 pts/42 00:02:28 ./test
519 26778 26325 26781 99 10 00:18 pts/42 00:02:28 ./test
519 26778 26325 26782 99 10 00:18 pts/42 00:02:28 ./test
519 26778 26325 26783 99 10 00:18 pts/42 00:02:28 ./test
519 26778 26325 26784 99 10 00:18 pts/42 00:02:28 ./test
519 26778 26325 26785 99 10 00:18 pts/42 00:02:27 ./test
519 26778 26325 26786 99 10 00:18 pts/42 00:02:28 ./test
519 26778 26325 26787 99 10 00:18 pts/42 00:02:28 ./test

如果把time.Sleep(time.Second)去掉后,马上全部执行结束。

1
2
3
[patrickxu@vm1 src]$ ./test
GOMAXPROCS = 8
x = 0

当然也可以把GOMAXPROCS设打,比如threads := runtime.GOMAXPROCS(10)。有足够多的P,也可以运行完。