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,也可以运行完。