Skip to content

Instantly share code, notes, and snippets.

@itczl22
Created October 11, 2019 13:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save itczl22/5c50d92e1a7f6a75e1e24efe71541842 to your computer and use it in GitHub Desktop.
Save itczl22/5c50d92e1a7f6a75e1e24efe71541842 to your computer and use it in GitHub Desktop.
多个goroutine之间内存同步问题
package main
import (
"fmt"
"time"
)
func main() {
var x, y int
go func() {
x = 1 // A1
fmt.Print("y:", y, " ") // A2
}()
go func() {
y = 1 // B1
fmt.Print("x:", x, " ") // B2
}()
time.Sleep(1 * time.Second)
}
// y:0 x:1
// x:0 y:1
// x:1 y:1
// y:1 x:1
// x:0 y:0
// 为什么会出现两个都是0的情况?
// 在现代计算机中可能会有多个处理器,每一个都会有自己的local cache
// 为了提升效率,对内存的写入一般会在每一个处理器中缓冲,并在必要时一起flush到主存
// 这种情况下这些数据可能会以与当初goroutine写入顺序不同的顺序被提交到主存
// 但是像channel通信或者互斥量操作这样的原语会使处理器将其写入及之前累积的写入全部flush并commit
// 这样goroutine在某个时间点上的执行结果才能被其它处理器上运行的goroutine得到
// 在一个独立的goroutine中,每一个语句的执行顺序是可以被保证的;也就是说goroutine是顺序连贯的
// 但是在不使用channel且不使用mutex这样的显式同步操作时,我们就没法保证事件在不同的goroutine中看到的执行顺序是一致的了
// 尽管goroutine A中一定需要观察到x=1执行成功之后才会去读取y,但它没法确保自己观察得到goroutine B中对y的写入,所以A还可能会打印出y的一个旧版的值
// 因为上边会出现00的情况,所以最好不要跨goroutine使用变量。如果要跨就得加锁
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment