// 情景1 package main import ( "fmt" ) var sum1, summain int64 func add1() { for i := 0; i < 1000; i++ { for j := 0; j < 10000; j++ { sum1++ } } } func main() { go add1() for i := 0; i < 10000; i++ { for j := 0; j < 10000; j++ { summain++ } } fmt.Println(sum1, sum1) } // 结果:10000000 100000000 // 解释: 1:由于main函数中的for 循环执行时间比较长,所以sysmon监控线程会对当前routine设置抢占标记 2:disassemble main.main 反汇编main函数发现,fmt.println() 调用的函数是runtime.convT2E(t *_type, elem unsafe.Pointer) 这里压入栈的数据是sum1的指针,但是这时函数首先调用morestack调度到另一个goroutine了,因此第一个结果为10000000 // 情景2 package main var sum1, summain int64 func add1() { for i := 0; i < 1000; i++ { for j := 0; j < 10000; j++ { sum1++ } } } func main() { go add1() for i := 0; i < 10000; i++ { for j := 0; j < 10000; j++ { summain++ } } println(sum1, sum1) } // 结果:0 100000000 解释: 1:同上 2: 反汇编之后发现println汇编实际调用的是runtime.printint 因此参数入栈的是sum1的初始值0,而后goroutine调度sum1虽然增加,但是printint的值是已经入栈的参数值所以第一个结果为0 当然如果这里把sysmon 停掉 //onM(newsysmon),结果就都是 0 0