浅谈go内存模型

Golang内存模型定义了在一个并发程序中,多个Goroutine对共享变量访问的行为。这里简单介绍一下我对Golang内存模型的理解。

基础理解

在Golang中,如果一个Goroutine在没有同步操作的情况下观察到另一个Goroutine的操作结果,那这种行为是没有保障的。也就是说,如果你要在多个Goroutine之间共享数据,你应该使用某种形式的同步。
考虑以下例子:

var a string
var done bool

func setup() {
    a = "hello, world"
    done = true
}

func main() {
    go setup()
    for !done {
    }
    print(a)
}

在上面的代码中,main函数可能会打印“hello, world”,也可能打印一个空字符串,甚至可能陷入无限循环,因为Goroutine中的操作可能对main函数不可见。

同步操作

为了在Goroutine之间正确地同步,你需要使用channel,或者使用sync包中的功能,如Mutex或WaitGroup。
以下是一个使用channel来同步的例子:

var a string

func setup() {
    a = "hello, world"
}

func main() {
    done := make(chan bool)
    go func(){
        setup()
        done <- true
    }()
    <-done
    print(a)
}

在这个例子中,main函数在打印a之前会等待setup函数完成,所以它总是打印出"hello, world"。

顺序一致性

Golang保证在单个Goroutine中,读和写操作会像在顺序一致的系统中一样执行。但是,不同Goroutine之间的操作顺序是由同步事件决定的。

示例:

var a, b int

func f() {
    a = 1
    b = 2
}

func g() {
    print(b)
    print(a)
}

func main() {
    go f()
    g()
}

在这个例子中,即使在f函数中a是在b之前设置的,g函数也可能先打印出b的值2,然后打印出a的值0。

Happens Before原则

在Golang中,理解并发编程和内存模型的关键是理解"happens before"的原则。如果在代码中,事件A happens-before事件B, 那么在所有的处理器上,事件A的影响对事件B都是可见的。

示例:

var a string
var done = make(chan bool)

func hello() {
    a = "hello, world"
    close(done)
}

func main() {
    go hello()
    <-done
    print(a)
}

在上述代码中,我们可以保证hello函数对a的写入操作 happens-before main函数中读取a的操作,因为写入操作在done通道关闭之前发生,而读取操作在done通道关闭后发生。

数据竞争与原子操作

同一个变量同时被多个goroutine读取和写入,而且他们之间没有明显的happens-before关系,这就会产生数据竞争。数据竞争可能会导致不可预见的结果,因此应该避免。

Golang的sync/atomic包提供了一系列原子操作,可以在并发环境中保证单一读/写操作是安全的。

示例:

var count uint64

func increment() {
    atomic.AddUint64(&count, 1)
}

func main() {
    for i := 0; i < 10; i++ {
        go increment()
    }
    time.Sleep(time.Second)
    finalCount := atomic.LoadUint64(&count)
    fmt.Println(finalCount)
}

在这个例子中,尽管有多个goroutine同时调用increment函数,但是对count的增加操作是原子的,不存在数据竞争。

总结

理解Golang的内存模型对于编写正确的并发代码至关重要。总的来说,我们应该避免在没有同步的情况下在多个goroutine之间共享变量,要理解和利用happens-before的原则,避免数据竞争,并有效地使用原子操作和同步原语。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值