package main
import (
"fmt"
"runtime"
"sync"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
var wg sync.WaitGroup
wg.Add(10)
for i := 0; i < 10; i++ {
go func(i int) {
fmt.Println(i)
wg.Done()
}(i)
}
// 1.14之前加上该行打印从0开始,之后版本则不影响
//time.Sleep(time.Second)
wg.Wait()
}
今天同事又问起了类似这样的面试题,目测出答案并不难。因为新创建的协程会进入_p_.runnext
,而之前的在_p_.runnext
中的协程则会被移动到_p_.runq
队列中,所以9先打印了之后才是按照大小依次打印。网上也有很多更详细的讲解。
不过让我想起来以前学习的时候,看大佬们讨论的另一个问题,就是上面代码中添加time.Sleep
的情况。所以记录一下,免得又半天想不起来为什么。
为什么多了一个time.Sleep
就顺序打印了?简单来说就是timer
会启动一个叫timerproc
的协程(源码地址),占用了runnext
。
不过在1.14版本对timer
实现更新后,timerproc
没了,上面的情况也就不会发生了,具体做了什么修改可以看其他大佬的深度解析
参考:
https://www.cyhone.com/articles/analysis-of-golang-timer/?highlight=time
https://zhuanlan.zhihu.com/p/31634188
http://xiaorui.cc/archives/6483