Go 内存模型.docVIP

  • 1
  • 0
  • 约4.53千字
  • 约 6页
  • 2016-02-24 发布于江苏
  • 举报
Go 内存模型.doc

简介 Go的内存模型详述了在一个groutine中对变量进行读操作能够侦测到在其他goroutine中对该变量的写操作的条件. Happens Before 对于一个goroutine来说,它其中变量的读, 写操作执行表现必须和从所写的代码得出的预期是一致的。也就是说,在不改变程序表现的情况下,编译器和处理器为了优化代码可能会改变变量的操作顺序即: 指令乱序重排。但是在两个不同的goroutine对相同变量操作时, 会因为指令重排导致不同的goroutine对变量的操作顺序的认识变得不一致。例如,一个goroutine执行a = 1; b = 2;,在另一个goroutine中可能会现感知到变量b先于变量a被改变。 为了解决这种二义性问题,Go语言中引进一个happens before的概念,它用于描述对内存操作的先后顺序问题。如果事件e1 happens before 事件 e2,我们说事件e2 happens after e1。如果,事件e1 does not happen before 事件 e2,并且 does not happen after e2,我们说事件e1和e2同时发生。 对于一个单一的goroutine,happens before 的顺序和代码的顺序是一致的。 如果能满足以下的条件,一个对变量v的读事件r可以感知到另一个对变量v的写事件w: 写事件w happens before 读事件r。 没有既满足 happens after w 同时满主 happens before r 的对变量v的写事件w。 为了保证读事件r可以感知对变量v的写事件,我们首先要确保w是变量v的唯一的写事件。同时还要满足以下条件: 写事件w happens before 读事件r。 其他对变量v的访问必须 happens before 写事件w 或者 happens after 读事件r。 第二组条件比第一组条件更加严格。因为,它要求在w和 r并行执行的程序中不能再有其他的读操作。 对于在单一的goroutine中两组条件是等价的,读事件可以确保感知到对变量的写事件。但是,对于在 两个goroutines共享变量v,我们必须通过同步事件来保证 happens-before 条件 (这是读事件感知写事件的必要条件)。 将变量v自动初始化为零也是属于这个内存操作模型。 读写超过一个机器字长度的数据,顺序也是不能保证的。 同步(Synchronization) 初始化 程序的初始化在一个独立的goroutine中执行。在初始化过程中创建的goroutine将在 第一个用于初始化goroutine执行完成后启动。 如果包p导入了包q,包q的init 初始化函数将在包p的初始化之前执行。 程序的入口函数 main.main 则是在所有的 init 函数执行完成 之后启动。 在任意init函数中新创建的goroutines,将在所有的init 函数完成后执行。 Goroutine的创建 用于启动goroutine的go语句在goroutine之前运行。 例如,下面的程序: var a string; func f() { print(a);} func hello() { a = hello, world; go f();} 调用hello函数,会在某个时刻打印“hello, world”(有可能是在hello函数返回之后)。 Channel communication 管道通信 用管道通信是两个goroutines之间同步的主要方法。通常的用法是不同的goroutines对同一个管道进行读写操作,一个goroutines写入到管道中,另一个goroutines从管道中读数据。 管道上的发送操作发生在管道的接收完成之前(happens before)。 例如这个程序: var c = make(chan int, 10)var a string func f() { a = hello, world; c - 0;} func main() { go f(); -c; print(a);} 可以确保会输出hello, world。因为,a的赋值发生在向管道 c发送数据之前,而管道的发送操作在管道接收完成之前发生。因此,在print 的时候,a已经被赋值。 从一个unbuffered管道接收数据在向管道发送数据完成之前发送。 下面的是示例程序: var c = make(chan int)var a string func f() { a = hello, world; -c;} fu

文档评论(0)

1亿VIP精品文档

相关文档