```go
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
var ok bool
cpuNu := runtime.NumCPU()
for i := 0; i < cpuNu; i++ {
go func() {
for {
if ok {
// to do
}
}
}()
}
time.Sleep(3 * time.Second)
fmt.Println("Not print...why???")
}
```
```go
package main
import (
"fmt"
"runtime"
"time"
)
//go:noinline
func addTest(a, b int) int {
return a + b
}
func call() {
addTest(1, 3)
}
func main() {
cpuNu := runtime.NumCPU()
for i := 0; i < cpuNu; i++ {
go func() {
for {
call() // 改为 addTest(1, 3) 依然不会打印
}
}()
}
time.Sleep(3 * time.Second)
fmt.Println("Not print...why???")
}
```
golang所谓的“有函数调用,就有了进入调度器代码的机会”,实际上是go编译器在函数的入口处插入了runtime.morestack_noctxt的函数调用,这个函数会检查是否扩容连续栈,并进入抢占调度的逻辑中。如果你调用的函数是直接可以确定函数栈的,没有插入runtime.morestack_noctxt,则不会被抢占。知道这些确实要对golang的调度器有很深的了解。
#8
更多评论
在写个限速的库,原本是用锁来实现的一些操作,后来改成原子操作,跑基准测试的时候发现的。试过其他语言不会这样,我想这种特殊场景暴露出goroutine调度的问题,可能是个坑。
#2