Golang Memery Model 内存模型

发布于 2022-01-16 12:53:31 字数 2245 浏览 1056 评论 0

在同一个 Goroutine 中,如果我们有下面的语句:

a = 1
b = 3

我们可以保证这几条赋值语句是按顺序执行的。但是,对于另一个 Goroutine 来说,它所观察到的顺序可能不是我们在代码里看到的顺序,比如,它可能先观察到 b = 3,然后 a = 1。至于原因可以了解一下 CPU 缓存一致性协议 MESI,以及有了MESI之后为什么还会有缓存一致性问题。

那这会造成什么问题呢?比如我们可以看一下下面这些有问题的代码:

var a, b int

func f() {
    a = 1
    b = 2
}
func main() {
    go f()
    print(a)
    print(b)
}

打印出来的 a 和 b 的值可能是赋值之后的,也可能是 0

再来看另一个有问题的代码:

var a string
var done bool

func setup() {
    a = "hello, world"
    done = true
}

func main() {
    go setup()
    for !done {}
    print(a)
}

我们创建了setup线程,用于对字符串a的初始化工作,初始化完成之后设置done标志为true。main函数所在的主线程中,通过for !done {}检测done变为true时,认为字符串初始化工作完成,然后进行字符串的打印工作。

但是Go语言并不保证在main函数中观测到的对done的写入操作发生在对字符串a的写入的操作之后,因此程序很可能打印一个空字符串。更糟糕的是,因为两个线程之间没有同步事件,setup线程对done的写入操作甚至无法被main线程看到(可能始终在CPU寄存器中),main函数有可能陷入死循环中。

因此,Go内存模型其实是一个概念,指定了某些条件,在这些条件下,可以保证在一个Goroutine中对一个共享变量的写入,可以被另一个Goroutine观察到。

什么是 Happens Before

就是字面意思,两个语句a = 1; b = 3只有三种情况:

  1. a = 1 happens before b = 3
  2. a = 1 happens after b = 3
  3. a = 1 and b = 3 happen concurrently

如果对一个变量的赋值操作w要保证被另一个读取操作r观察到,运用 Happens before 概念,我们可以得出需要满足如下条件:

  • w happens before r
  • 任何其他对变量的赋值操作要么happens before w,要么happens after r

下面介绍一些在Go编程中可以确定是 happens before 的语句(不全,更详细的可以参考官方文档)

init()

如果在package a中导入了package b,那么package binit() happens before package ainit()

channel

  • 对一个channel的发送操作 happens before 接收操作完成
  • 对一个channel进行close() happens before 接收到零值
  • 对一个无缓冲channel的接收操作 happens before 发送操作完成(意思就是发送会阻塞,直到被接收)
  • 带缓冲的channel也是一样,超出缓冲区的发送会阻塞

对于最开始的那几段有问题的代码,解决办法就是通过同步原语来给两个事件明确排序。可以用sync.Mutex(),也可以用``channel

推荐阅读

关于 Golang Memory Model,就推荐一篇文章,官方文章,讲的很清楚

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84961 人气
更多

推荐作者

醉城メ夜风

文章 0 评论 0

远昼

文章 0 评论 0

平生欢

文章 0 评论 0

微凉

文章 0 评论 0

Honwey

文章 0 评论 0

qq_ikhFfg

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文