Все знают самую знаменитую пословицу Роба Пайка: "Не общайтесь, разделяя память; разделяйте память, общаясь".
Джун читает это и делает вывод: «Мьютексы - это устаревшее зло из C++, каналы - это тру-Go-вей!». И после этого пишет 50 строк кода с горутиной-координатором,
select и каналами просто для того, чтобы безопасно инкрементировать счетчик просмотров или обновить мапу.Сеньор смотрит на это и грустит, потому что знает секрет: под капотом любого канала (в структуре
hchan) лежит... обычный мьютекс. Использовать канал просто для защиты переменной - это как купить таксопарк, чтобы один раз съездить за хлебом.Давайте раз и навсегда проведем границу.
🛡 Когда берем Мьютексы (Состояние)
Если ваша задача - защитить кусок данных (структуру,
map, срез) от одновременного изменения, берите sync.Mutex или sync.RWMutex.- Это быстро: Взять свободный мьютекс - это дешевая атомарная операция (~15-20 наносекунд). Операции с каналами тяжелее, так как требуют работы с внутренними очередями и планировщиком.
- Это просто:
mu.Lock() и defer mu.Unlock(). Никаких рисков забыть закрыть канал и получить утечку горутины (Goroutine Leak).- Идеальный юзкейс: In-memory кэши, хранение сессий, счетчики внутри структур.
🚦 Когда берем Каналы (Оркестрация и Владение)
Каналы нужны не для защиты данных, а для передачи владения (ownership) и управления потоком выполнения.
- Передача эстафеты: Одна горутина скачала кусок данных, отдала его в канал и "забыла" про него. Вторая горутина забрала и начала парсить.
- Оркестрация: Worker Pools, пайплайны (Fan-Out/Fan-In), о которых мы говорили раньше.
- Таймауты и отмены: Вы не можете прервать ожидание
mu.Lock() по таймауту. А вот конструкцию select { case <-ch: ... case <-time.After(1*time.Second): ... } - легко.❌ Классический Антипаттерн:
Создавать отдельную "горутину-хранитель", которая владеет мапой и слушает каналы
chanGet и chanSet, чтобы отдавать и записывать значения. Это ад в отладке, работает медленнее мьютекса и требует написания кучи бойлерплейта.✅ Золотое правило (одобрено разработчиками Go):
- Используйте каналы для маршрутизации данных и контроля за горутинами.
- Используйте мьютексы для защиты внутреннего состояния (state) ваших объектов.
🔥 Senior Tip: Атомики
Если вам нужно защитить не сложную структуру, а просто инкрементировать счетчик или переключить флаг (число или
bool), не берите ни мьютексы, ни каналы. Ваш выбор - пакет sync/atomic.Операция
atomic.AddInt64 выполняется на уровне аппаратных инструкций процессора (CAS) и работает так быстро, что вы даже не увидите её в профайлере.#golang #concurrency #architecture #bestpractices #cleancode
📲 Мы в MAX
👉 @golang_lib