go lang中的同步不正确不正确、go、lang

2023-09-07 16:30:50 作者:ζ  劳资特么那么好

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

While I was taking a look on the golang memory model document(link), I found a weird behavior on go lang. This document says that below code can happen that g prints 2 and then 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'后出现)谁能清楚地告诉我这个问题吗?

Is this only go routine issue? Because I am curious that why value assignment of variable 'b' can happen before that of 'a'? Even if value assignment of 'a' and 'b would happen in different thread(not in main thread), does it have to be ensured that 'a' should be assigned before 'b' in it's own thread?(because assignment of 'a' comes first and that of 'b' comes later) Can anyone please tell me about this issue clearly?

推荐答案

变量 ab 被分配并初始化为各自类型的零值(即0 如果是 int) 在任何函数开始执行之前,在这一行:

Variables a and b are allocated and initialized with the zero values of their respective type (which is 0 in case of int) before any of the functions start to execute, at this line:

var a, b int

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

What may change is the order new values are assigned to them in the f() function.

引用该页面:发生在之前:

在单个 goroutine 中,读取和写入必须按照程序指定的顺序执行.也就是说,编译器和处理器可以重新排序在单个 goroutine 中执行的读取和写入,仅当重新排序不会改变语言规范定义的 goroutine 内的行为时.由于这种重新排序,一个 goroutine 观察到的执行顺序可能与另一个 goroutine 观察到的顺序不同.例如,如果一个 goroutine 执行 a = 1;b = 2;,另一个可能会在 a 的更新值之前观察到 b 的更新值.

Within a single goroutine, reads and writes must behave as if they executed in the order specified by the program. That is, compilers and processors may reorder the reads and writes executed within a single goroutine only when the reordering does not change the behavior within that goroutine as defined by the language specification. Because of this reordering, the execution order observed by one goroutine may differ from the order perceived by another. For example, if one goroutine executes a = 1; b = 2;, another might observe the updated value of b before the updated value of a.

ab 的分配可能不会按照您编写它们的顺序发生,如果重新排序它们不会在同一个 goroutine 中产生差异.例如,如果首先更改 b 的值更有效(例如,因为它的地址已经加载到寄存器中),编译器可能会重新排序它们.如果更改分配顺序会(或可能)在同一个 goroutine 中导致问题,那么显然不允许编译器更改顺序.由于 f() 函数的 goroutine 在赋值后对变量 ab 什么都不做,编译器可以自由执行以任何顺序分配.

Assignment to a and b may not happen in the order you write them if reordering them does not make a difference in the same goroutine. The compiler may reorder them for example if first changing the value of b is more efficient (e.g. because its address is already loaded in a register). If changing the assignment order would (or may) cause issue in the same goroutine, then obviously the compiler is not allowed to change the order. Since the goroutine of the f() function does nothing with the variables a and b after the assignment, the compiler is free to carry out the assignments in whatever order.

由于上例中的 2 个 goroutine 之间没有同步,因此编译器不会检查重新排序是否会导致另一个 goroutine 出现任何问题.没必要.

Since there is no synchronization between the 2 goroutines in the above example, the compiler makes no effort to check whether reordering would cause any issues in the other goroutine. It doesn't have to.

Buf 如果你同步你的 goroutine,编译器将确保在同步点"不会有不一致:你将保证在那个点两个分配都将完成";因此,如果同步点"在 print() 调用之前,那么您将看到打印的分配的新值:21.

Buf if you synchronize your goroutines, the compiler will make sure that at the "synchronization point" there will be no inconsistencies: you will have guarantee that at that point both the assignments will be "completed"; so if the "synchronization point" is before the print() calls, then you will see the assigned new values printed: 2 and 1.