Go学习 Day23 内存模型

64 阅读2分钟

由于指令重排,代码并不一定会按照你写的顺序执行,go语言的内存模型提供了一定的顺序保证。

happens-before关系:定义两个事件(读、写)的顺序:如果事件e1 happens before事件e2,即事件e2在事件e1之后发生(happens after)。如果e1不是 happens before e2, 也不是happens after e2,那么可以说事件 e1 和 e2 同时发生。

GO语言中提供了一些针对happens-before关系的保证:

1)init函数:
    a)应用程序的初始化是在单一的 goroutine 执行的。如果包 p 导入了包 q,那么,q的init函数的执行一定 happens before p 的任何初始化代码;
    b)main 函数一定在导入的包的 init 函数之后执行。
2)变量:
    a)包级别的变量在同一个文件中是按照声明顺序逐个初始化的,除非初始化它的时候依赖其它的变量,针对这种情况,Go会利用依赖分析技术确保初始化正确,依赖分析技术保证的顺序只是针对同一包下的变量,且只有引用关系是本包变量、函数和非接口的方法,才能保证它们的顺序性。
    b)同一个包下的多个文件,会按照文件名的排列顺序进行初始化
3)goroutine:
    a)启动goroutine的go语句happens before此goroutine内的代码执行;
    b)goroutine 退出的时候,是没有任何 happens-before 保证的。
4)Channel:
    a)往Channel中的发送操作,happens before从该Channel接收相应数据的动作完成之前,即第n个send一定happens before第n个receive的完成;
    b)close 一个 Channel 的调用,肯定 happens before 从关闭的 Channel 中读取出一个零值;
    c)对于 unbuffered 的 Channel,从此Channel中读取数据的调用一定happens before往此Channel 发送数据的调用完成
    d)如果 Channel 的容量是 m(m>0),那么第 n 个 receive 一定 happens before 第 n+m 个 send 的完成
5)Mutex/RWMutex:
    a)第 n 次的 m.Unlock 一定 happens before 第 n+1 m.Lock 方法的返回
    b)读写锁的 Lock 必须等待既有的读锁释放后才能获取到
6)WaitGroup:Wait 方法等到计数值归零之后才返回
7)Once:对于 once.Do(f) 调用,f 函数的那个单次调用一定 happens before 任何 once.Do(f) 调用的返回
8)atomic:未给出任何的保证

此文章为2月Day23学习笔记,内容来源于极客时间《Go 并发编程实战课》