在查看golang内存模型文档(link)时,我发现go lang上有一个奇怪的行为。该文档说,下面的代码可能会发生,g依次打印2和0。

var a, b int

func f() {
    a = 1
    b = 2
}

func g() {
    print(b)
    print(a)
}

func main() {
    go f()
    g()
}

这是例行公事吗?因为我很好奇为什么变量'b'的值赋值可以先于'a'赋值?即使'a'和'b的值分配将在不同的线程中发生(不是在主线程中),是否也必须确保在其自己的线程中将'a'分配在'b'之前?(因为分配' a'首先出现,'b'之后出现)有人可以清楚地告诉我这个问题吗?

最佳答案

在开始执行任何功能之前,在以下行中分配变量ab并使用其各自类型的零值(对于0而言,为int)进行初始化,在此行:

var a, b int

可能会改变的是f()函数中将新值分配给它们的顺序。

从该页面引用:Happens Before:



如果重新排序ab在同一个goroutine中没有区别,则可能不会按照您编写它们的顺序进行分配。例如,如果首先更改b的值更有效(例如,因为其地址已加载到寄存器中),则编译器可能会对其重新排序。如果在同一goroutine中更改分配顺序会(或可能)引起问题,那么显然不允许编译器更改顺序。由于f()函数的goroutine在赋值后对变量ab不执行任何操作,因此编译器可以自由执行任意顺序的赋值。

由于在上面的示例中这两个goroutine之间没有同步,因此编译器不费力气检查重新排序是否会在另一个goroutine中引起任何问题。不必。

另外,如果您对goroutine进行同步,则编译器将确保在“同步点”不会出现任何不一致之处:您将确保在这时两个分配都将“完成”;因此,如果“同步点”在print()调用之前,那么您将看到打印的已分配新值:21

09-10 09:59
查看更多