Примитивы параллельного и конкурентного программирования в Node.js — от мьютексов и семафоров до распределённых блокировок Redis и worker-пулов.
- Sync-примитивы (Mutex)
- Sync-примитивы (Semaphore)
- Async-примитивы
- Бенчмарки Atomics
- Lock-free
- Распределённые блокировки
- Worker Threads
- Worker Pools
- Стек технологий
- Установка и запуск
Кросс-потоковая синхронизация через SharedArrayBuffer + Atomics.
| Модуль | Описание |
|---|---|
| Mutex-1 | Реализация на Atomics.exchange() + Atomics.wait() |
| Mutex-2 | Реализация на Atomics.compareExchange() |
| Mutex-3-broken | Намеренно сломанная реализация (для демонстрации ошибок) |
| Async Mutex | Обёртка поверх Mutex с async/await интерфейсом |
Дополнительно:
- Deadlock — два потока захватывают блокировки в разном порядке
- Livelock (2 варианта) — потоки постоянно уступают друг другу без прогресса
- Point race condition — демонстрация гонки на структуре данных (x, y) и её устранение через Mutex
src/sync-primitives/mutex/
Бинарные и счётные семафоры на Atomics.
| Модуль | Описание |
|---|---|
| Race condition demo | 22 воркера делятся на 2 группы — гонка без защиты |
| Binary semaphore (naive) | Наивная реализация на флаге — небезопасна |
| Binary semaphore (atomics) | Корректная реализация через Atomics.compareExchange() |
| Binary semaphore (atomics v2) | Альтернативная атомарная реализация |
| Counting semaphore | Общий счётный семафор — допускает N одновременных участников |
src/sync-primitives/semaphore/
Координация конкурентных async-операций внутри одного потока (event loop), без SharedArrayBuffer.
| Примитив | Описание |
|---|---|
| AsyncMutex | Взаимное исключение через FIFO-очередь промисов. Защита in-memory состояния, соединений к БД |
| AsyncSemaphore | Ограничение конкурентности до N задач (аналог p-limit). Демо: 10 URL с макс. 3 параллельными запросами |
| Barrier | Точка синхронизации: все N участников должны дойти до барьера, прежде чем любой продолжит. Поддержка повторного использования через генерации. Демо: кросс-поточный барьер через SharedArrayBuffer |
| BoundedChannel | Async MPSC-канал с backpressure (вдохновлён Go/Rust). send() блокирует при заполнении, receive() — при пустом буфере |
| AsyncRWLock | Множество читателей ИЛИ один писатель. Write-preferring (предотвращает голодание писателей) |
| Token Bucket | Классический алгоритм rate limiting — допускает кратковременные всплески до capacity (AWS API Gateway, nginx) |
| Sliding Window | Строгий rate limiter — ровно N запросов в окне, без всплесков (GitHub API) |
src/async-primitives/
Сравнение стратегий атомарных операций на 15 потоках × 100M инкрементов.
| Файл | Стратегия |
|---|---|
1-atomics.ts |
Базовый Atomics.add() на общем буфере |
2-sharding.ts |
Шардирование — каждый поток в свой SharedArrayBuffer |
3-int.ts |
Обычные Int32Array-операции |
4-non-atomic-sharding.ts |
Шардирование без атомарности (демонстрация проблем) |
5-workerpool-atomic.ts |
Atomics.add() через npm workerpool |
6-workerpool-int.ts |
Int-операции через workerpool |
src/atomic-benchmarks/
CAS-счётчик (Compare-And-Swap) — основа lock-free структур данных.
Алгоритм: Atomics.load() → вычисление нового значения → Atomics.compareExchange() → retry при contention.
Бенчмарк: CAS loop vs Atomics.add() vs Mutex.
src/lock-free/cas-counter.ts
Распределённый мьютекс на Redis (SET NX EX).
- Атомарный захват блокировки с TTL
- Атомарное освобождение через Lua-скрипт (проверка владельца)
- Watchdog auto-renewal — автопродление TTL при долгих операциях
- Экспоненциальный backoff + jitter при retry
- Защита от deadlock: авто-истечение при падении процесса
Применение: cron-задачи, миграции, leader election между инстансами.
Для запуска демо нужен Redis:
docker run -d -p 6379:6379 redissrc/distributed/redis-lock/
Базовые паттерны работы с worker_threads.
| Модуль | Описание |
|---|---|
| Single-file worker | Один файл как main и worker (isMainThread), передача workerData, postMessage() |
| Image resize | Ресайз изображений через sharp в воркерах (1920×, 1280×, 640×) |
| Express + bcrypt server | Express-сервер с CPU-интенсивным bcrypt.hash(). Два варианта: 1 воркер и 4 воркера |
src/worker-thread/
Пулы воркеров с очередями задач.
| Модуль | Описание |
|---|---|
| Кастомная реализация | Собственный WorkerPool с idle-map, очередью задач, цепочкой then2() |
| Bcrypt-бенчмарки | Express-сервер: без пула ~60 req/sec, с workerpool ~8700 req/sec |
| Video resize | Ресайз видео через fluent-ffmpeg + StaticPool из node-worker-threads-pool |
| workerpool vs worker-threads | Сравнение npm workerpool и нативных worker_threads — бенчмарки производительности |
src/worker-pool/
- Node.js
worker_threads,Atomics,SharedArrayBuffer - ioredis — Redis-клиент для распределённых блокировок
- express + helmet + morgan — HTTP-сервер
- bcrypt — CPU-интенсивное хэширование паролей
- sharp — обработка изображений
- fluent-ffmpeg — обработка видео
- workerpool, node-worker-threads-pool — пулы воркеров
npm install
# Запуск любого модуля
npx tsx src/<путь-к-файлу>.ts
# Примеры
npx tsx src/sync-primitives/mutex/1-mutex-base.ts
npx tsx src/async-primitives/async-semaphore/demo-concurrent-requests.ts
npx tsx src/distributed/redis-lock/demo.ts
npx tsx src/worker-pool/2-bcrypt-experiments/server.ts