Материал проходит вычитку — возможны неточности.
Урок 99 из 118

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 для больших структур
Задание · вопросы

Проверьте себя

Вопрос 1 из 3

Пара связанных полей (сумма и количество) обновляется всегда вместе. Атомик или мьютекс?

Вопрос 2 из 3

Снимок конфига мутируют прямо после Get. Что скажет -race?

Вопрос 3 из 3

Что делает copy-on-write с конфигом?

Итоги

atomic.Pointer + неизменяемые данные = снимки без блокировок. Атомик — для одиночного значения, мьютекс — для связанных инвариантов.

Наш сайт собирает куки. Чтобы тебе было удобнее им пользоваться. Нажимая на кнопку, ты даёшь разрешение собирать куки