并发 Go 程序中的共享变量 (四):内存同步

栏目: Go · 发布时间: 6年前

内容简介:本系列是阅读 “The Go Programming Language” 理解和记录。在上一小节中但是不像

本系列是阅读 “The Go Programming Language” 理解和记录。

在上一小节中 并发 Go 程序中的共享变量 (三):读写锁 ,我们在实现 Balance 方法也需要一个排他锁,不论这个排他锁是通过 channel 实现还是互斥锁实现都是可以的,在我们的例子中是通过 读写锁 实现的。

func Balance()int {
    mu.RLock()
    defer mu.RUnlock()
    return balance
}

但是不像 Deposit 方法那样需要读取 balance 并且加上 amount, Balance 只有一种操作,就是读取 Balance 并返回,所以即使有其它的 goroutine 在这中间有执行操作也不会造成什么问题。真的是这样么?

实际上我们还是需要锁,理由有二:

第一, Balance 不能在其他操作执行期间执行,比如 Withdraw 执行中的时候,实际上已经少了 balance,但是实际读取的 balance 可能还是一个旧值。

第二,同步不仅仅和 goroutine 的执行顺序相关,同步也会影响内存。

在现代计算机中,一般都会有多个 CPU,每个有 CPU 有自己的主存缓存。为了性能,写到主存的数据一般都会在每个 CPU 内部首先缓存起来,然后在必要的时候提交到主存。 这些修改的提交的顺序可能和 goroutine 的执行顺序不同 。而同步原语比如说 channel 或者互斥锁的主要目的就是让 CPU 把 buffer 的数据提交到主存中,以便其它执行在其它 CPU 上的 goroutine 能够看到这些提交带来变化。

考虑以下代码的输出:

var x, y int
go func(){
    x = 1                   // A1
    fmt.Print("y:", y, " ") // A2
}()

go func(){
   y = 1                    // B1
   fmt.Print("x:", x, " ")  // B2
}()

正如前面文章所提到的, 两个 goroutine 并发执行,而且在没有使用互斥机制的情况下共享变量,存在 data race ,因此在看到不确定的结果时不应该感到惊讶。我们可能会看到由于代码的执行顺序的不同而有不同的输出:

y:0 x:1
x:0 y:1
x:1 y:1
y:1 x:1

这四行输出可以解释为 A1,B1,A2,B2 或者 B1,A1,A2,B2。但是有一种结果可能会让你感到吃惊:

x:0 y:0
y:0 x:0

但是现实情况是:由于 CPU 或者编译器以及其它一些因素的影响,这种结果是有可能发生的。那么这 4 句语句如何交错执行才能产生这样的结果?

在单个 goroutine 中,每个语句带来的影响可以说是严格按照他们的执行顺序而产生的,goroutine 是线性一致的(sequentially consistent)。但是在多个 goroutine 中, 如果没有显式的同步机制,比如 channel 或者互斥锁,没有办法保证 goroutine 彼此之间看到影响都是严格按照执行顺序的先后而产生的 。虽然 goroutine A 肯定是先观测到 x = 1 执行完毕之后才去读取 y 的值,但是它没有办法确保 goroutine B 对 y 的修改一定能看的到,所以 goroutine A 可能读取的还是一个 y 的旧值:0。

理解并发执行的这种尝试常常很有意思,就好像并发的结果确实是 goroutine 之间的这些语句交错执行而产生的,事实可能并不是如此,正如上面的例子展示出来的一样结果都是 0 的输出,goroutine 的执行完全由可能是 A2,A1,B2,B1。这是由于赋值语句和 Print 语句指向都是不同的变量,编译器可能会得出一个论是: 这两条语句的执行结果相互不影响从而交换了这两条语句的执行顺序 。如果这两个 goroutine 是在不同的 CPU 上执行,每个 CPU 都有自己的 cache,其中一个 goroutine 写到 cache 中的数据是不能被另一个 goroutine 中的 Print 语句看到的,直到数据被同步到主从中。

所有并发的问题都能被这些已经建立的简单模式所解决:

要么保证变量只在单个 goroutine 中使用;

要么在多个 goroutine 之间使用互斥锁。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

产品觉醒:产品经理的视角与方法论

产品觉醒:产品经理的视角与方法论

判官(李泽澄) / 电子工业出版社 / 2018-11 / 59.80元

《产品觉醒:产品经理的视角与方法论》是作者多年工作经验的汇集,通过自己亲身经历来对产品运营、行业和人生选择做一个全面的复盘,为读者提供有一定深度的分析。 《产品觉醒:产品经理的视角与方法论》共7章,第1章介绍了产品经理应该具有的视角来分析和观察产品分析方法;第2章介绍了做产品时如何破局来解决相应的问题;第3章介绍了在做产品经理前先分析自己;第4章介绍了怎么来解决执行力的问题;第5章介绍了怎么......一起来看看 《产品觉醒:产品经理的视角与方法论》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具