Go 1.14之前的死循环Case
第一个例子
package main
import (
"runtime"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
go func() {
for {
}
}()
time.Sleep(time.Millisecond)
println("OK")
}
不会打印OK
为什么不会打印?
> [golang高并发模型](https://www.yangyanxing.com/article/golang-concurrency.html)第二个例子
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
for i := 0; i < runtime.NumCPU(); i++ {
go func() {
for {
}
}()
}
for {
time.Sleep(100)
fmt.Println(time.Now())
}
}
也是打印一会儿之后就卡死了。
第三个例子
func main() {
var count int32 =0
for i:=0;i<=10;i++ {
go func() {
for {
atomic.AddInt32(&count,1)
}
}()
go func() {
for {
fmt.Println(count==1)
}
}()
}
time.Sleep(time.Hour)
}
打印一会儿之后,程序会卡死。
表面上看 atomic.AddInt32(&count,1)
有函数调用,那这里为什么还是卡死了呢。
=我是分割线====
因为此"函数调用"非彼"函数调用"。
思考一个问题:
Q: 如何判断某个语句是否会导致函数调用呢?
A: 就是把他们反汇编之后看这些语句是否对应着CALL指令就知道了。
我们分别看一下fmt.Println
和atomic.AddInt32
的反汇编代码就知道了。查看反汇编的指令go tool compile -S main.go
所以我们可以看到atomic.AddInt32
是不会触发函数调用的,fmt.Println
会触发函数调用的,进而可以检查自己的抢占flag,决定是否继续执行,还是让出自己。
感谢go夜读群友的提问和讨论,使得我可以更深入理解抢占式调度的含义。PS.这个问题是我解决的,哈哈哈。