Як обробляти завдання з високим навантаженням на процесор у Node.js без блокування основного потоку

Node.js чудово підходить для одночасного виконання багатьох завдань, таких як читання файлів або виконання мережевих запитів. Але коли мова йде про важкі завдання, такі як обробка зображень або виконання складних обчислень, це може сповільнити роботу і зупинити реагування на інші запити. Це трапляється, тому що Node.js працює на одному потоці, і велике завдання може заблокувати все інше.

pic

Як обробляти важкі завдання з високим навантаженням на процесор в Node.js без блокування основного потоку

У цьому блозі ми розглянемо способи обробки таких важких завдань у Node.js без блокування основного потоку. Ми зробимо це просто і покажемо приклади, щоб допомогти вам зрозуміти.

Чому варто уникати блокування основного потоку?

Node.js використовує один потік для обробки всіх завдань. Якщо важке завдання займає цей потік:

  • Інші запити змушені чекати: Додаток не може обробляти нові завдання, поки не завершиться важке.
  • Користувачі відчувають затримки: Ваш додаток стає повільним або не реагує.

Щоб виправити це, ми можемо перенести важкі завдання на інші потоки або процеси, щоб основний потік залишався вільним.

Способи обробки важких завдань

1. Використання Worker Threads

Worker Threads дозволяють виконувати код в паралельних потоках. Це означає, що важкі завдання не блокують основний потік.

Приклад: Обробка зображень з Worker Threads

 // worker.js  
const { parentPort, workerData } = require('worker_threads');  
const sharp = require('sharp');  

const processImage = async (file) => {  
 try {  
 await sharp(file).resize(200, 200).toFile('output.jpg');  
 parentPort.postMessage('Обробка зображення завершена');  
 } catch (error) {  
 parentPort.postMessage(`Помилка: ${error.message}`);  
 }  
};  

processImage(workerData.file);

2. Використання Child Processes

Модуль child_process дозволяє виконувати завдання в окремих процесах. Це дозволяє основному потоку залишатися вільним.

Приклад: Обробка зображень з Child Processes

 // child.js  
const sharp = require('sharp');  

process.on('message', async (data) => {  
 try {  
 await sharp(data.file).resize(200, 200).toFile('output.jpg');  
 process.send('Обробка зображення завершена');  
 } catch (error) {  
 process.send(`Помилка: ${error.message}`);  
 }  
});

3. Використання Message Queues

Для більших додатків ви можете використовувати черги повідомлень, такі як Redis або RabbitMQ, щоб відправляти завдання на обробку іншим сервісам. Таким чином, основний додаток обробляє запити, поки робочі процеси обробляють завдання.

const Queue = require('bull');  
const sharp = require('sharp');  

const imageQueue = new Queue('image processing', 'redis://127.0.0.1:6379');  

imageQueue.process(async (job) => {  
 const { file } = job.data;  
 await sharp(file).resize(200, 200).toFile('output.jpg');  
 return { status: 'completed' };  
});  

imageQueue.add({ file: 'image.jpg' });  

imageQueue.on('completed', (job, result) => {  
 console.log(`Завдання ${job.id} завершено з результатом:`, result);  
});  

imageQueue.on('failed', (job, err) => {  
 console.error(`Завдання ${job.id} не вдалося з помилкою:`, err);  
});

Кращі практики

  1. Слідкуйте за продуктивністю: Використовуйте інструменти, такі як clinic.js, щоб знаходити повільні завдання.
  2. Використовуйте ефективні бібліотеки: Вибирайте ефективні бібліотеки, такі як sharp, для завдань, таких як обробка зображень.
  3. Масштабуйте розумно: Додавайте більше робочих процесів за потреби.
  4. Встановлюйте обмеження: Контролюйте, скільки пам'яті та процесора можуть використовувати робочі процеси.

Висновок

Важкі завдання в Node.js можуть уповільнити ваш додаток, але ви можете уникнути цього, перемістивши ці завдання на окремі потоки, процеси або сервіси. Такі варіанти, як Worker Threads, Child Processes, Message Queues або Native Addons, допомагають зберігати ваш додаток швидким і чуйним.

Виберіть найкращий метод в залежності від потреб вашого додатка. З цими стратегіями ви забезпечите плавну роботу вашого додатка, навіть при важких завданнях.

Перекладено з: How to Handle High CPU-Intensive Tasks in Node.js Without Blocking the Main Thread

Leave a Reply

Your email address will not be published. Required fields are marked *