Go语言内存模型
名词定义 执行体 - Go里的Goroutine或Java中的Thread
背景介绍 内存模型的目的是为了定义清楚变量的读写在不同执行体里的可见性。理解内存模型在并发编程中非常重要,因为代码的执行顺序和书写的逻辑顺序并不会完全一致,甚至在编译期间编译器也有可能重排代码以最优化CPU执行, 另外还因为有CPU缓存的存在,内存的数据不一定会及时更新,这样对内存中的同一个变量读和写也不一定和期望一样。
和Java的内存模型规范类似,Go语言也有一个内存模型,相对JMM来说,Go的内存模型比较简单,Go的并发模型是基于CSP(Communicating Sequential Process)的,不同的Goroutine通过一种叫Channel的数据结构来通信;Java的并发模型则基于多线程和共享内存,有较多的概念(violatie, lock, final, construct, thread, atomic等)和场景,当然java.util.concurrent并发工具包大大简化了Java并发编程。
Go内存模型规范了在什么条件下一个Goroutine对某个变量的修改一定对其它Goroutine可见。
Happens Before 在一个单独的Goroutine里,对变量的读写和代码的书写顺序一致。比如以下的代码:
package main import ( "log" ) var a, b, c int func main() { a = 1 b = 2 c = a + 2 log.Println(a, b, c) } 尽管在编译期和执行期,编译器和CPU都有可能重排代码,比如,先执行b=2,再执行a=1,但c=a+2是保证在a=1后执行的。这样最后的执行结果一定是1 2 3,不会是1 2 2。但下面的代码则可能会输出0 0 0,1 2 2, 0 2 3 (b=2比a=1先执行), 1 2 3等各种可能。
package main import ( "log" ) var a, b, c int func main() { go func() { a = 1 b = 2 }() go func() { c = a + 2 }() log.
[Read More]