atomic.Pointer и выбор †
Корень бага нашёлся: конфигурация публиковалась по полям, и воркер прочитал половину старых настроек и половину новых. Миша собрал hot-reload на atomic.Pointer: новая версия публиковалась целиком, воркеры брали снимок. Аня на ревью напомнила про мьютекс для связанных полей.
atomic.Pointer[T] публикует указатель на неизменяемые данные — читатели берут снимок без блокировок; атомик выбирают для одиночного значения, мьютекс — для связанных инвариантов.
Публикация неизменяемого состояния
type Config struct {
Timeout time.Duration
}
var cfg atomic.Pointer[Config]
func Update(c *Config) {
cfg.Store(c) // публикуем новый конфиг
}
func Get() *Config {
return cfg.Load() // снимок
}
Писатель собирает новый Config целиком (мутирует локальную копию, не трогая опубликованную) и одним Store делает её видимой. Читатели Load-ят снимок и работают с ним, не боясь, что он изменится под ними. Данные после публикации никто не мутирует — поэтому блокировки не нужны.
Паттерн copy-on-write
func SetTimeout(d time.Duration) {
old := cfg.Load()
newCfg := *old // копия
newCfg.Timeout = d
cfg.Store(&newCfg)
}
Правка идёт через копию: прочитали, скопировали, изменили копию, опубликовали. Старый объект продолжают держать читатели, которым он достался раньше, — и это безопасно, потому что он неизменяем. Это copy-on-write: дорого только для больших структур, для конфигов — идеально.
Атомик или мьютекс
Счётчик — канонический пример мьютекса и одновременно антипример: для простого инкремента мьютекс избыточен, есть атомики. Мьютекс нужен, когда инвариант сложнее «прибавить единицу»: обновить два связанных поля, проверить условие и изменить состояние, обновить карту. Одиночный счётчик — как раз случай, где выбирают атомарную операцию.
Вы узнаете:
- чем
atomic.Pointerудобнееatomic.Value - какова цена copy-on-write для больших структур
Проверьте себя
Пара связанных полей (сумма и количество) обновляется всегда вместе. Атомик или мьютекс?
Снимок конфига мутируют прямо после Get. Что скажет -race?
Что делает copy-on-write с конфигом?
правильных ответов
atomic.Pointer + неизменяемые данные = снимки без блокировок. Атомик — для одиночного значения, мьютекс — для связанных инвариантов.
10 000 ₽ · 60 минут · онлайн