Compare-and-swap
Счётчик обработанных байтов недосчитывал: несколько воркеров прибавляли одновременно, и часть записей терялась. Миша переписал инкремент на atomic.Add, и после ночного прогона счётчик впервые сошёлся с S3.
CAS — «запиши новое значение, только если там всё ещё старое»: операция возвращает, удалась ли замена, и на ней строят циклы обновления без блокировок.
Что такое CAS
Что здесь показано
- Стек — локальные переменные функции.
i = 3— значение;p = ptr → 10— указатель на значение;b = "hello"— срез (заголовок: указатель + длина + ёмкость). - Куча — данные, на которые ссылаются переменные:
rodata— байты строки-литерала (в бинарнике),данные N Б— бэкинг-массив слайса,строка— динамическая строка. - Горутины — лёгкие потоки Go: статус (running/runnable/waiting…), функция, в которой каждая сейчас находится, размер стека (растёт по мере работы) и пометка «из main» — горутина запущена из твоего кода.
- GC — сборщик мусора: фаза (off/mark) и число завершённых циклов.
CAS атомарно проверяет текущее значение и, если оно совпало с ожидаемым, заменяет его. Это «если-затем-записать» как одна неделимая операция — то, чего не хватало обычным if n == 0 { n = 1 }, где между проверкой и записью вклинивалась другая горутина.
CAS-loop
Если CAS не удался, значение тем временем изменил кто-то другой. Стандартный паттерн — повторить:
for {
old := n.Load()
new := old * 2
if n.CompareAndSwap(old, new) {
return new
}
// не вышло: кто-то изменил — перечитываем и пробуем снова
}
Цикл «прочитал — посчитал — попробовал записать» с повтором и есть CAS-loop. При умеренной конкуренции он быстрее мьютекса: нет блокировок, нет очередей — только редкие повторы при столкновениях.
Где живёт CAS
Add — отдельная аппаратная атомарная read-modify-write операция (на amd64 это инструкция LOCK XADD), а не цикл CAS под капотом. Явный CAS нужен, когда обновление не сводится к «прибавить»: удвоить, обменять местами, записать максимум. Любое «прочитал — вычислил новое из старого» на общей переменной — кандидат на CAS-loop.
Вы узнаете:
- когда CAS-loop дешевле мьютекса
- как устроен lock-free стек на CAS
Проверьте себя
Между Load и CompareAndSwap значение прошло путь A → B → A. Что сделает CAS?
Почему «if Load == 0 { Store }» не заменяет CAS?
Для чего ABA-проблема действительно опасна?
правильных ответов
CAS — атомарная «если старое, то новое»; CAS-loop — неблокирующее обновление с повтором при столкновениях. Add — отдельный аппаратный примитив (LOCK XADD), а не цикл CAS. Основа lock-free счётчиков и структур.
10 000 ₽ · 60 минут · онлайн