func main() {
runtime.GOMAXPROCS(1)
go func() {
for i:=0;i<10 ;i++ {
fmt.Println(i)
}
}()
for {}
}
预想的是for独占M, goroutine不会执行,但是结果却是goroutine正常输出,这是为何?
0
1
2
3
4
5
6
7
8
9
我的go版本是:
☁ etc go version
go version go1.17 darwin/amd64
我记得这个问题在《go语言高级编程》中提过。 求大佬们帮忙释怀。。。
有疑问加站长微信联系(非本文作者)
因为新版本的golang解决了你说的这个问题。
执行
go tool compile -S test1.go > xx.txt
你会发现for {}
实际上被优化了,根本就不是一个循环你确定不是go的调度 把阻塞的 协程放到其他cpu运行了?对for做了优化,没看懂这个 优化成啥了
golang是抢占式的调度,如果一个协程阻塞,调度器会把cpu剥夺,让给其他协程。目的就是防止某个协程占用过多的cpu时间,防止其他协程饿死。
这种无法单凭某一个文件某一段代码就找到明确答案和依据的题目,很容易炸出“裸泳”者。
这个是go1.14版本更新时实现了基于信号的抢占式调度
Windows操作系统从95版开始、Linux从2.0内核都是抢先式多任务了,保护模式和CPU核心数无瓜,哪怕只有一个核心的保护模式也支持抢先式多任务。golang协程只是使用了操作系统的特性而已。
你确定看过抢占的实现过程?
嗯教科书上是这么说的,实际测试也相符,一个核心也能输出。 如果想独占CPU的一个核心,在Windows上有相应的系统API,以前使用过。
之前是利用morestack插入了一段检测代码。但如代码,如果不涉及func调用,而是一个for{},那其他协程就一直得不到执行机会。 1.14实现了基于信号量的抢占式调度,其他协程也能得到执行机会了
以前确实会,查看状态一个核心是100%占用,后面版本不会了。
应该是因为协程的CPU占用时长问题,超过10ms会强制性把该协程放到global队列