Доводилось ли работать с многопоточностью в Node.js
Что проверяют
Понимаете ли вы, где в Node.js вообще есть потоки, и отличаете ли CPU-нагрузку от I/O. Вопрос про опыт, поэтому ждут конкретный случай, а следом спрашивают, почему в той задаче не хватило обычного async/await.
Как отвечать
Сначала короткая модель:
- event loop: JavaScript выполняется в одном потоке, и тяжёлый синхронный код (разбор большого JSON, хэширование, ресайз картинок) блокирует все запросы разом;
- пул libuv: потоки под капотом уже есть, по умолчанию 4, размер задаёт
UV_THREADPOOL_SIZE. На нём работаютfs,dns.lookup,crypto.pbkdf2,zlib. Сетевой ввод-вывод идёт через механизмы ОС и пул не занимает; worker_threads: отдельный V8-изолят со своим event loop и памятью. Данные идут черезpostMessageкопированием,ArrayBufferможно передать без копии через transfer list, общая память только черезSharedArrayBufferиAtomics;clusterи PM2 в cluster mode: это процессы, а не потоки. Они раскидывают соединения по ядрам, но одну тяжёлую задачу не ускорят.
Дальше ваш случай: что тормозило и как это измерили (задержка event loop через perf_hooks.monitorEventLoopDelay, профиль через --cpu-prof), что вынесли в воркеры, как устроили пул (piscina или свой), какие цифры получили до и после. Цифры нужны ваши, реальные.
Если опыта не было, так и скажите и покажите, что знаете, когда он понадобится: «задач на CPU в проде не встречалось, но генерацию PDF-отчётов я бы вынес в пул воркеров, а не создавал поток на каждый запрос».
Где спотыкаются
Ставят воркеры на I/O вроде запросов к базе. Это только добавляет накладных расходов: асинхронный ввод-вывод и так не блокирует поток.
Создают новый Worker на каждую задачу. Запуск изолята стоит времени и памяти, нужен пул с очередью.
Рассказывают про мьютексы. Воркеры по умолчанию память не делят, гонки появляются только с SharedArrayBuffer, и решают их через Atomics, а чаще передачей сообщений без общего состояния.