Является ли потокобезопасным доступ к различным членам структуры в go?

Безопасно ли обращаться к различным членам структуры из разных goroutines?

Я понимаю, что запись в одну и ту же переменную без синхронизации dangareous:

package main

type Apple struct {
    color string
    size  uint
}

func main() {
    apple := &Apple{}
    go func() {
        apple.color = "red"
    }()
    go func() {
        apple.color = "green"
    }()
}

Но можете ли вы писать для разных членов структуры без какой-либо синхронизации?

package main

type Apple struct {
    color string
    size  uint
}

func main() {
    apple := &Apple{}
    go func() {
        apple.color = "red"
    }()
    go func() {
        apple.size = 42
    }()
}

Или я должен использовать chan или sync.Mutex для этого?

Ответ 1

Необходимо иметь доступ к различным переменным из разных потоков, а члены структуры - разные переменные. Поэтому да, это должно быть безопасно.

Однако это может быть не быстро. Переменные, близкие по объему в памяти, такие как члены структуры, будут совместно использовать линию кэша ЦП. Линия кеша - это наименьшая часть памяти, которую может блокировать процессор (ну, большинство современных моделей). Это означает, что CPU-2 должен ждать записи до тех пор, пока CPU-1 не закончит эту строку кэша, даже если они пишут разные переменные.

Невозможно изменить указатель на структуру при записи в структуру из разных потоков. В вашем примере, если у вас есть третий goroutine, который сделал apple = &Apple{}, некоторые из других goroutines в других потоках могут писать в старое Apple или новое Apple, и вы не знаете.