最近一位非常热心的网友建议结合demo来分析一下goroutine的调度器,而且还提供了一个demo代码,于是便有了本文,在此对这位网友表示衷心的感谢!
这位网友提供的demo程序可能有的gopher以前见过,已经知道了具体原因,但本文假定我们是第一次遇到这种问题,然后从零开始,通过一步一步的分析和定位,最终找到问题的根源及解决方案。
虽然本文不需要太多的背景知识,但最好使用过gdb或delve调试工具,了解汇编语言及函数调用栈当然就更好了。
本文我们需要重点了解下面这3个内容。
调试工具无法准确显示函数调用栈时如何找到函数调用链;
发生GC时,如何STOP THE WORLD;
什么时候抢占调度不会起作用以及如何规避。
本文的实验环境为AMD64 Linux + go1.12
Demo程序及运行现象
package main import( "fmt" "runtime" "time" ) func deadloop() { for { } } func worker() { for { fmt.Println("worker is running") time.Sleep(time.Second * 1) } } func main() { fmt.Printf("There are %d cores.\n", runtime.NumCPU()) goworker() godeadloop() i := 3 for { fmt.Printf("main is running, i=%d\n", i) i-- if i == 0 { runtime.GC() } time.Sleep(time.Second * 1) } }