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

Ответ

Нет, по умолчанию структуры в Go не являются потокобезопасными. Если несколько горутин одновременно обращаются к данным одной и той же структуры, и хотя бы одна из них выполняет запись, возникает состояние гонки (data race), что приводит к непредсказуемому поведению программы.

Go придерживается принципа "не общайтесь через разделяемую память, а разделяйте память через общение". Однако для ситуаций, где необходим прямой доступ к общим данным, существуют механизмы синхронизации:

  1. Мьютексы (sync.Mutex и sync.RWMutex): Самый распространенный способ. Mutex предоставляет эксклюзивный доступ, а RWMutex позволяет множество читателей или одного писателя.
  2. Каналы (channels): Идиоматичный способ Go для безопасной передачи данных между горутинами.
  3. Атомарные операции (sync/atomic): Для простых операций над примитивными типами (например, инкремент счетчика), которые выполняются без блокировок и являются более производительными.

Пример с sync.Mutex:

type SafeCounter struct {
    mu    sync.Mutex
    count int
}

func (c *SafeCounter) Increment() {
    c.mu.Lock() // Блокируем доступ для других горутин
    defer c.mu.Unlock() // Гарантируем разблокировку в конце функции
    c.count++
}

func (c *SafeCounter) Value() int {
    c.mu.Lock()
    defer c.mu.Unlock()
    return c.count
}