go lang的同步不正确 [英] Incorrect synchronization in go lang

查看:129
本文介绍了go lang的同步不正确的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我查看golang内存模型文档(链接)时,我发现一个奇怪的行为去朗。这个文件说,下面的代码可能会发生g打印2,然后0。

  var a,b int 

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

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

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

这是唯一的常规问题吗?因为我很好奇,为什么变量'b'的值赋值会在'a'之前发生?即使'a'和'b'的值赋值会在不同的线程中发生(不在主线程中),是否必须确保'a'应该在它自己的线程中的'b'之前被赋值?(因为赋值' a'首先,'b'的更晚)任何人都可以清楚地告诉我这个问题吗?

变量 a b 被分配并初始化为它们各自类型的零值(它是 0 在任何函数开始执行之前,在 int )之前:

  var a,b int 

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



从该页面引用:发生在前


<在单个goroutine中,读取和写入必须像表现得一样y按程序指定的顺序执行。也就是说,编译器和处理器可能会重新排序在单个goroutine中执行的读取和写入操作,只有当重新排序不会改变语言规范定义的goroutine内的行为时。由于这种重新排序,一个goroutine观察到的执行顺序可能与另一个看到的顺序不同。例如,如果一个goroutine执行 a = 1; b = 2; ,另一个可能会观察 b 更新后的<

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

因为上面的两个goroutine之间没有同步例如,编译器不会检查重新排序是否会导致其他goroutine中的任何问题。它不需要。



如果你同步你的goroutines,编译器会确保在同步点不会有矛盾:你将会拥有保证当时这两项任务都将完成;所以如果同步点在 print()调用之前,那么您将看到分配的新值被打印出来: 2 1


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()
}

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?

解决方案

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

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

Quoting from that page: Happens Before:

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.

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.

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 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.

这篇关于go lang的同步不正确的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆