go的内存模型:并发环境中多 goroutine 读相同变量的时候,变量的可见性条件。
- 什么条件下goroutine 在读取一个变量的值的时候,能够看到其它 goroutine 对这个变量进行的写的结果。
为什么会出现这个问题:
- 因为会发生指令重排和多级Cache的存在,使得多线程同时访问同一个变量的可见性和顺序需要一个规范。这个规范叫做内存模型。
为什么定义内存模型:
- 想程序员提供一种保证,在面对同一个数据同时被多个goroutine访问的情况,可以做一些串行化访问的控制,比如使用channel或者sync包和sync/atomic包中的并发原语
- 允许编译器和硬件对程序做一些优化
指令重排和可见性问题
程序在运行的时候,两个操作的顺序可能不会得到保证。重排以及多核 CPU 并发执行导致程序的运行和代码的书写顺序不一样。但是,如果某些操作能够提供happens-before关系,我们就可以100%保证指令运行的顺序。
在一个goroutine 内部,程序的执行顺序和它们的代码指定的顺序是一样的。对于另一个 goroutine 来说,重排却会产生非常大的影响。因为 Go 只保证 goroutine 内部重排对读写的顺序没有影响。即一个线程内部的执行顺序对另一个线程来说是不确定的。
Go内存模型通过happens-before定义两个事件的顺序,要么先发生要么后发生,否则认为是同时。
tips:
- 在 Go 语言中,对变量进行零值的初始化就是一个写操作。
- 如果对超过机器 word(64bit、32bit 或者其它)大小的值进行读写