Ответ
И 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может оказаться быстрее.
Ответ 18+ 🔞
А, ну ты про мьютексы, да? Вот эта вся хуйня с горутинами, где они как тараканы по кухне бегают и в одну кастрюлю с борщом лезут. Так, слушай, сейчас разжую.
Вот представь: у тебя есть переменная, общая, на всех. И горутины, эти ебушки-воробушки, все к ней одновременно тянутся. Одна хочет прочитать, другая — записать, третья уже с хуя ли? Короче, пиздец, а не состояние гонки. Чтобы этого не было, нам и нужны эти замки — Mutex и RWMutex.
sync.Mutex — это как один сортир на всю стройку.
Железное правило: кто первый зашёл — тот и царь. Закрылся, сделал свои дела, вышел — тогда следующий. Неважно, ты просто пописал или насрал так, что плитку сносить надо. Доступ эксклюзивный, блядь.
Lock()— это ты дёргаешь ручку, а она не открывается. Стоишь, ждёшь, терпения ноль ебать, пока предыдущий мудак не выйдет.Unlock()— это ты вышел и дверь открыл. Следующий, заходи, страдай.
sync.RWMutex — это уже поумнее система, как библиотека.
Тут правила хитрее, но логичные:
- Либо один писатель заходит в отдельный кабинет и там творит свою хуйню. Никто его не трогает.
- Либо много читателей могут одновременно сидеть в читальном зале и листать одну и ту же книгу. Главное — чтобы в кабинете писателя никого не было.
У него два типа ключей:
- Ключ от кабинета писателя (
Lock/Unlock) — тот же самый сортир, эксклюзив. Один в один какMutex. - Ключ от читального зала (
RLock/RUnlock) — взял брошюрку, почитал, положил на место. Пока писатель не пришёл, читателей может быть овердохуища.
Вот, смотри, как это в коде выглядит, не пугайся:
var (
rw sync.RWMutex // Наш продвинутый замок с двумя режимами
data int // Общая переменная, из-за которой весь сыр-бор
)
// Куча горутин может делать это одновременно — читательский режим
rw.RLock() // "Ребят, я просто посмотреть!"
value := data // Читаем данные
rw.RUnlock() // "Всё, посмотрел, свободно!"
// А вот это — эксклюзив. Только одна горутина за раз.
rw.Lock() // "Всем стоять! Я ща буду менять всё нахуй!"
data = 42 // Запись, ёпта
rw.Unlock() // "Готово, можете снова суетиться."
Так когда что брать? Сука, думай головой!
-
Берёшь
Mutex, когда:- Записываешь часто. Ну или когда тебе похуй на оптимизацию и проще везде воткнуть один простой замок, чем думать.
- Логика доступа — пиздопроебибна, там не разберёшь, где чтение, а где запись. Закрыл на общий замок — и спи спокойно.
-
Берёшь
RWMutex, когда:- У тебя читают постоянно, а пишут раз в год по обещанию. Классика — кеш какой-нибудь или конфиг, который грузится при старте.
- Вот тут он реально даёт прирост, потому что читатели друг другу не мешают.
Но! Не думай, что RWMutex — это магия. У него свои накладные расходы, управление этими двумя очередями — не халява. Если у тестя конкуренция низкая или ты пишешь каждую миллисекунду, то обычный Mutex может оказаться даже шустрее. Вот такой, блядь, парадокс.
Короче, правило простое: если не уверен — бери Mutex. А как начнёшь в профайлере видеть, что все горутины в очереди на чтение стоят — вот тогда уже думай про RWMutex. Всё, вопрос закрыт, иди работай.