TGViewer
Настоящий JavaScript Настоящий JavaScript @true_js · 5.89K subscribers
Post #3643 314
⁣Atomics.pause() в спин-локах: когда хинт процессору превращается в баг кэш-когерентности

На первый взгляд, Atomics.pause() выглядит как безобидная микро-оптимизация: подсказываем процессору, что поток в спин-локе, и он сам оптимизирует кэш. В production с Worker-пулами на 8+ потоках и SharedArrayBuffer эта иллюзия разбивается о когерентность кэша и деградацию производительности.

Ложное пробуждение и протокол MESI
Atomics.pause() не даёт реальной задержки — процессор просто крутит микро-циклы. Когда десяток воркеров висят на Atomics.load() с прикрученным pause(), протокол когерентности (MESI) начинает бешено спамить состоянием Shared->Invalid. Кэш-промахи растут, latency скачет до 100 микросекунд. Типичная ошибка: думать, что pause() автоматически синхронизирует кэш — это не так, он лишь сообщает планировщику о намерении.

Дедлоки из-за локального кэша
Если пишешь цикл спин-лока только через Atomics.load() + pause(), без Atomics.wait(), то длительность паузы неопределённая. Поток может застрять на устаревшем значении в локальном L1-кэше из-за отсутствия барьера памяти. Пример из практики: в API-клиенте с shared очередь запросов на Node.js подняли буст, но через 30 секунд 25% запросов ушли в таймаут — поток просто не видел обновлённый флаг.
while (Atomics.load(flag, 0) !== DONE) {
Atomics.pause(); // баг: нет гарантии выхода
// счётчик ложноных выходов растёт
}

Практический совет: ограничь число итераций. Первые 10 — один pause(), до 100 — два, потом — Atomics.wait() с таймаутом. Иначе спин-лок съедает все такты ЦП.

NUMA-архитектуры и прыжки задержки
На AMD EPYC или Intel Xeon каждый pause() триггерит инвалидацию L1/L2, затем обновление через QPI или Infinity Fabric. Задержка скачет в 10-100 раз. В Worker-пуле, разбросанном по разным ядрам, это убивает пропускную способность. Решение — привязка воркеров к сокету через navigator.hardwareConcurrency (браузер) или os.setPriority (Node.js) с группировкой по архитектуре.

Предупреждение: не используй Atomics.pause() сам по себе в высоконагруженных пулах — это прямая дорога к деградации кэша и скачкам памяти. Тестируй под конкретный процессор.

Вывод: Atomics.pause() — это хинт, а не панацея, и в реальных спин-локах без комбинации с экспоненциальным backoff и Atomics.wait() он приносит больше вреда, чем пользы.
More from @true_js
  1. Oct 2, 2026😅 Айтишник отправил в одну компанию три одинаковых резюме и только одно дошло до финала О…
  2. Oct 2, 2026Post #3961
  3. Oct 2, 2026🤣 Правильно расставленные приоритеты в моей жизни би лайк: 💥 xCode Journal
  4. Oct 1, 2026🤯 Люди взбунтовались против «пыточной для ИИ» На GitHub заметили открытый проект AI Tortu…
  5. Oct 1, 2026День в Заонежье начинается ещё в дороге. Мы встретим вас в аэропорту или на вокзале. Дальш…
  6. Sep 30, 2026Книга из переписки без сервера: canvas, jsPDF и брошюра для печати прямо в браузере Пет-пр…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →