В чём разница между `sync.Mutex` и `sync.RWMutex` в Go?

Ответ

И Mutex, и RWMutex — это примитивы синхронизации в Go, предназначенные для защиты разделяемых данных от состояния гонки. Однако они решают эту задачу по-разному и оптимизированы для разных сценариев.

sync.Mutex (Взаимное исключение)

Mutex предоставляет эксклюзивную блокировку. Это означает, что только одна горутина может владеть блокировкой в любой момент времени, независимо от того, читает она данные или пишет.

  • Lock(): Захватывает блокировку. Если она уже занята, горутина блокируется до её освобождения.
  • Unlock(): Освобождает блокировку.

sync.RWMutex (Блокировка чтения-записи)

RWMutex предоставляет раздельную блокировку, оптимизированную для сценариев, где чтений гораздо больше, чем записей. Правило работы:

  • Либо один писатель может захватить блокировку.
  • Либо множество читателей могут одновременно захватить блокировку.

Он имеет два типа блокировок:

  • Блокировка на запись (Lock/Unlock): Работает как обычный Mutex — эксклюзивный доступ.
  • Блокировка на чтение (RLock/RUnlock): Позволяет неограниченному числу горутин одновременно читать данные, но только если нет активной блокировки на запись.

Пример:

var (
    rw   sync.RWMutex
    data int
)

// Множество горутин могут выполнять этот код одновременно
rw.RLock() 
fmt.Println("Читаем данные:", data)
rw.RUnlock()

// Только одна горутина может выполнять этот код
rw.Lock()
data++ // Запись
rw.Unlock()

Ключевые отличия и когда что использовать:

  • Сценарий:

    • Mutex: Используйте, когда операции записи происходят часто или когда логика доступа к данным сложна и проще использовать одну эксклюзивную блокировку.
    • RWMutex: Идеален для структур данных, которые редко изменяются, но часто читаются (например, кеш конфигурации).
  • Производительность:

    • RWMutex может значительно повысить производительность в read-heavy сценариях.
    • Однако RWMutex имеет больше накладных расходов, чем Mutex. Если конкуренция за ресурс низкая или операции записи частые, Mutex может оказаться быстрее.