在go中访问struct的不同成员是否安全?

Kam*_*zic 15 mutex sync go

从不同的goroutines访问不同的struct成员是否安全?

我明白,在没有同步的情况下写入同一个变量是很糟糕的:

package main

type Apple struct {
    color string
    size  uint
}

func main() {
    apple := &Apple{}
    go func() {
        apple.color = "red"
    }()
    go func() {
        apple.color = "green"
    }()
}
Run Code Online (Sandbox Code Playgroud)

但是你可以在没有任何同步的情况下写入不同的struct成员吗?

package main

type Apple struct {
    color string
    size  uint
}

func main() {
    apple := &Apple{}
    go func() {
        apple.color = "red"
    }()
    go func() {
        apple.size = 42
    }()
}
Run Code Online (Sandbox Code Playgroud)

或者我应该使用chansync.Mutex为此?

Zan*_*ynx 16

从不同的线程访问不同的变量应该是安全的,而struct成员是不同的变量.所以是的它应该是安全的.

但是,它可能不会很快.与结构成员一样在内存中靠近的变量将共享CPU缓存行.缓存行是CPU(最好的,大多数当前型号)可以锁定的最小内存.这意味着CPU-2必须等待写入,直到CPU-1完成该缓存行,即使它们正在写入不同的变量.

从不同的线程写入结构时,更改指向结构的指针是不安全的.在你的例子中,如果你有第三个goroutine apple = &Apple{}在其他线程中做了一些其他goroutine可能写入旧Apple或新Apple,你不会知道.

  • 第1和第3段很棒; 第2段似乎偏离主题(因为关注是安全)和糟糕的建议(因为Go是如此高级的语言,你应该默认编写最具表现力的代码,并根据具体情况优化需要的地方 - 一般不应用这个理由.不能保证这些goroutine甚至可以被不同的CPU执行!). (4认同)
  • 第二段对于那些正在考虑更大问题的人有帮助:并发访问struct字段的问题是什么?我对最后一段感到担忧,因为它会将指针与结构本身混淆.可以修改结构,而其他一些goroutine恰好修改指向该结构的指针. (3认同)