// 情景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
有疑问加站长微信联系(非本文作者)