代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package main

import (
"fmt"
"runtime"
"sync"
)

func main() {

runtime.GOMAXPROCS(1)

var wg sync.WaitGroup
for i := 1; i <= 10; i++ {
wg.Add(1)
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}

wg.Wait()
}

结果

1
2
3
4
5
6
7
8
9
10
10
1
2
3
4
5
6
7
8
9

疑问

为什么不是 0-1-2-3-4-5-6-7-8-9-10 呢?为什么 10 会在最前面呢?

源码分析

源码地址:https://golang.org/src/runtime/proc.go?h=func%20runqput line=4690

1
2
3
4
5
6
7
8
9
10
11
12
if next {
retryNext:
oldnext := _p_.runnext
if !_p_.runnext.cas(oldnext, guintptr(unsafe.Pointer(gp))) {
goto retryNext
}
if oldnext == 0 {
return
}
// Kick the old runnext out to the regular run queue.
gp = oldnext.ptr()
}

这段代码的意思是 go 会把每个 P 所管理的最后一个 goroutine 放入 next 位置。为什么??

这是 go 设计认为或者是有过测试:如果一个 P 的 goroutine 队列在顺序执行的时候,因为 go sched 会有很多抢占或者调度。那么从被执行的概率上来分析的话,放入一个 next 位置可使得每个 goroutine 的执行概率是相当的。