这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战
Go内存模型
软件(编译器)或硬件(CPU)系统可以根据其对代码的分析结果,一定程度上打乱代码的执行顺序,以达到其不可告人的目的(提高 CPU 利用率) from 曹大
- 可见性:GO 内存模型阐明了一个goroutine对某变量的写入,如何才能保证被另一个读取该变量的goroutine监测到。
- 事件的发成次序:程序在修改被多个goroutine同时访问的数据时必须序列化该访问。
要序列化访问,需要通过channel,或其它像sync和sync/atomic包中的同步原语来保护数据。
Happens Before(事件的发生次序)
定义
若事件e1发生在e2之前,那么我们就说e2发生在e1之后。换言之,若e1既未发生在e2之前,又未发生在e2之后,那么我们就说e1与e2是并发的。
解释
在单个goroutine中,事件发生的顺序即为程序所表达的顺序。
仅在不会改变语言规范对goroutine行为的定义时,编译器和处理起才会对读取和写入的顺序进行重新排序。
由于存在重新排序,一个goroutine监测到的执行顺序可能与另一个goroutine监测到的不同。例如,若一个goroutine执行a=1;b=2;
,另一个goroutine可能监测到b的值先与a更新。
1 | diff复制代码单goroutine的情形: |
同步
初始化
程序的初始化运行在单个goroutine中,但该goroutine可能会创建其它并发运行的goroutine。
若包p导入了包q,则q的init函数会在p的任何函数启动前完成。
函数main.main会在所有的init函数结束后启动。
goroutine的创建
go
语句会在当前goroutine开始执行前启动新的goroutine。
The
go
statement that starts a new goroutine happens before the goroutine’s execution begins.
这个不是很理解要表达的是什么意思(通过go
关键字创建一个新的goroutine的动作发生在goroutine执行之前?)
1 | go复制代码var a string |
goroutine的销毁
goroutine无法确保在程序中的任何事件发生之前退出。(在不使用同步原语保护的情况下)
1 | go复制代码var a string |
例如:goroutine无法确保在打印前完成对变量a的赋值,因为对a进行赋值后并没有任何同步事件,因此无法保证被其它goroutine监测到(可以使用channel来解决)
本文转载自: 掘金