Що таке worker threads у Node.js?
Потоки Робітників у Node.js
Потоки Робітників (впроваджені в Node.js 10, стабільні в 12) дозволяють виконувати JavaScript у паралельних потоках в межах одного процесу. На відміну від модуля Cluster (який створює окремі процеси), потоки робітників ділять пам'ять і призначені для обчислювальних задач.
Коли Використовувати Потоки Робітників
| Сценарій використання | Рекомендовано |
|---|---|
| Операції вводу/виводу (файл, мережа) | ❌ Цикл подій справляється з цим добре |
| Важкі обчислення (МЛ, хешування, парсинг) | ✅ Потоки Робітників |
| Паралельні HTTP сервери | ❌ Використовуйте Cluster |
| Обробка зображень/відео | ✅ Потоки Робітників |
| Блокуючі синхронні бібліотеки | ✅ Потоки Робітників |
Основний Приклад
js
// worker.js
const { workerData, parentPort } = require('worker_threads');
function heavyComputation(n) {
let result = 0;
for (let i = 0; i < n; i++) result += Math.sqrt(i);
return result;
}
const result = heavyComputation(workerData.n);
parentPort.postMessage(result); // відправити результат назадjs
// main.js
const { Worker } = require('worker_threads');
function runWorker(workerData) {
return new Promise((resolve, reject) => {
const worker = new Worker('./worker.js', { workerData });
worker.on('message', resolve);
worker.on('error', reject);
worker.on('exit', (code) => {
if (code !== 0) reject(new Error(`Потік робітника завершився з кодом ${code}`));
});
});
}
// Основний потік НЕ заблокований!
runWorker({ n: 1e9 }).then(result => {
console.log('Результат:', result);
});
console.log('Основний потік продовжує виконання...');Спільна Пам'ять з SharedArrayBuffer
js
// main.js
const { Worker } = require('worker_threads');
const sharedBuffer = new SharedArrayBuffer(4); // 4 байти
const sharedArray = new Int32Array(sharedBuffer);
sharedArray[0] = 0;
const worker = new Worker(`
const { workerData } = require('worker_threads');
const shared = new Int32Array(workerData.sharedBuffer);
shared[0] = 42; // запис у спільну пам'ять
`, {
eval: true,
workerData: { sharedBuffer }
});
worker.on('exit', () => {
console.log('Спільне значення:', sharedArray[0]); // 42
});Шаблон Пулу Потоків Робітників
Для виробничого використання створіть пул для повторного використання робітників:
js
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads');
const os = require('os');
class WorkerPool {
constructor(workerFile, size = os.cpus().length) {
this.workers = Array.from({ length: size }, () => ({
worker: new Worker(workerFile),
busy: false
}));
this.queue = [];
}
run(data) {
return new Promise((resolve, reject) => {
const free = this.workers.find(w => !w.busy);
if (free) {
this._execute(free, data, resolve, reject);
} else {
this.queue.push({ data, resolve, reject });
}
});
}
_execute(entry, data, resolve, reject) {
entry.busy = true;
entry.worker.postMessage(data);
entry.worker.once('message', result => {
entry.busy = false;
resolve(result);
if (this.queue.length > 0) {
const next = this.queue.shift();
this._execute(entry, next.data, next.resolve, next.reject);
}
});
entry.worker.once('error', reject);
}
}Потоки Робітників vs Cluster
| Потоки Робітників | Cluster | |
|---|---|---|
| Процес | Один і той же процес | Окремі процеси |
| Пам'ять | Можуть ділити (SharedArrayBuffer) | Окрема пам'ять |
| Комунікація | Швидка (MessagePort) | Повільніша (IPC) |
| Найкраще для | Обчислень ЦП | Масштабування мережі |
| Ізоляція | Нижча | Вища (аварія процесу) |
Резюме
Потоки Робітників вирішують найбільше обмеження Node.js: обчислювальні задачі, які блокують цикл подій. Використовуйте їх для важких обчислень — але для більшості задач, пов'язаних з вводу/виводу, цикл подій справляється з паралелізмом ідеально без потоків.
Коротка відповідь
Для співбесідиPremium
Коротка відповідь допоможе вам впевнено відповідати на цю тему під час співбесіди.