本文来自小天同学的投稿,233作为一个不会Golang的Java渣渣都看懂一些了。看完只能感慨是时候开始学Go了!强烈推荐给正在学习Golang或者对Golang感兴趣的小伙伴,建议收藏~
前言
本文主要是对The Go Memory Model一文的翻译,也想借此机会加深对golang内存模型的理解。
介绍
go内存模型规定了某个goroutine的读操作保证能观测到来自其他goroutine对这个变量的写操作的一组条件。
建议
那些数据在修改的同时如果被其他goroutine访问到,必须串行化(serialize)这种访问才能保证数据的安全性。
为了串行化访问,通过channel或者其他同步原语比如sync
和sync/atomic
包来保护数据。
如果你必须阅读这篇文档剩下的内容以理解你的程序的行为,你将会变得太聪明。
永远不要聪明。
Happens Before
在单个goroutine里,读和写必须表现得好像它们在按照程序指定的顺序执行。
也就是,编译器和处理器可能重排序(reorder)单个goroutine内执行的读和写,当然重排序不会改变语言规范所定义的在这个goroutine内的行为。因为重排序的存在,一个goroutine观测到的执行顺序可能和其他goroutine观测到的不同。
举个栗子,如果一个goroutine执行a = 1; b = 2;另外一个goroutine可能观测到对变量b的更新先于a
为了规定读和写的依赖,我们定义了happens before,一个部分有序的执行
。
如果事件e1 happens before 事件e2,那我们说e2 happens after e1。另外,如果e1没有happens before e2同时e2没有happens before e1,那我们说e1和e2并发地发生。
在单goroutine环境,happens-before顺序就是程序所表达的顺序。
在下面两个条件满足时,对变量v的读r允许观测到对v的写w:
1. r没有happen before w
2. 没有其他对v的写w' happens after w并happen before r
要保证对变量v的读观测到对v的特定写w,w是唯一允许被r观测到的写。即是,r被保证观测到w需要同时满足下列两个条件:
1. w happens before r
2. 任何其他对变量v的写要么happens before w要么happens after r
这对条件比第一对更强,它需要没有其他写和w或者r并发地发生。
笔记:第一对条件是允许观测,第二对条件是保证观测,约束强度不一样。
在单goroutine环境,没有并发,所以这两个定义是等价的:一个读r观测到最近的对这个变量的写w。
当多个goroutine同时访问一个共享变量v,它们必须使用同步事件来建立happens-befor