Latest Post

🚀 Hướng dẫn chi tiết về Worker Threads trong Node.js Cách giải phóng bộ nhớ sau mỗi lần trim ảnh với thư viện trim-image trong Node.js

Worker Threads trong Node.js là một cơ chế giúp thực hiện đa luồng (multi-threading), cho phép chạy các tác vụ nặng về CPU mà không ảnh hưởng đến hiệu suất của luồng chính (Event Loop).

💡 Tại sao cần Worker Threads?

  • Node.js vốn là single-threaded, tức là chỉ có một luồng thực thi chính.
  • Khi gặp tác vụ nặng về tính toán, luồng chính sẽ bị đóng băng, làm chậm cả ứng dụng.
  • Worker Threads giúp chạy các tác vụ này trên luồng riêng, không ảnh hưởng đến hiệu suất tổng thể.

📌 Ứng dụng thực tế:
Xử lý ảnh, video, âm thanh (Sharp, FFmpeg, Puppeteer)
Mã hóa / Giải mã dữ liệu (AES, RSA, zlib)
AI / Machine Learning (TensorFlow.js, OpenCV)
Xử lý dữ liệu lớn, tính toán phức tạp

📌 Lợi ích:
✔ Tăng tốc xử lý bằng cách chạy nhiều Worker song song
Không làm chậm Event Loop, giúp ứng dụng phản hồi nhanh hơn
✔ Dễ dàng mở rộng, phù hợp với ứng dụng có nhiều tác vụ CPU nặng

🔥 1. Worker Threads là gì?

Worker Threads trong Node.js là một cách để chạy mã JavaScript đa luồng (multi-threading).
Mặc dù Node.js sử dụng một luồng chính (single-threaded), nhưng nhờ worker_threads, bạn có thể chạy các tác vụ nặng trên các luồng riêng mà không làm ảnh hưởng đến hiệu suất của chương trình chính.

📌 Ứng dụng của Worker Threads:
✅ Xử lý ảnh, video, âm thanh (ví dụ: sharp, trim-image)
✅ Nén, mã hóa dữ liệu (ví dụ: zlib, crypto)
✅ Tính toán nặng như AI, Machine Learning, Blockchain
✅ Xử lý dữ liệu lớn (big data)

🔥 2. Cách tạo một Worker Thread cơ bản

📌 Ví dụ: Tạo một Worker thực hiện tính tổng từ 1 đến N

🔹 Bước 1: Tạo file chính main.js

const { Worker } = require('worker_threads');

function runWorker(n) {
    return new Promise((resolve, reject) => {
        const worker = new Worker('./worker.js', { workerData: { num: n } });

        worker.on('message', (result) => resolve(result)); // Nhận kết quả từ Worker
        worker.on('error', reject);
        worker.on('exit', (code) => {
            if (code !== 0) reject(new Error(`Worker exited with code ${code}`));
        });
    });
}

async function main() {
    const result = await runWorker(1000000);
    console.log(`✅ Tổng từ 1 đến 1000000 là: ${result}`);
}

main();

🔹 Bước 2: Tạo file Worker worker.js

const { parentPort, workerData } = require('worker_threads');

function sum(n) {
    let total = 0;
    for (let i = 1; i <= n; i++) total += i;
    return total;
}

const result = sum(workerData.num);
parentPort.postMessage(result); // Gửi kết quả về `main.js`

👉 Chạy lệnh:

node main.js

📌 Kết quả:

✅ Tổng từ 1 đến 1000000 là: 500000500000

💡 Lợi ích:

  • Chương trình chính không bị chậm, vì tính toán chạy trên luồng riêng.
  • Dễ dàng mở rộng để xử lý nhiều tác vụ song song.

🔥 3. Chạy nhiều Worker đồng thời (Multi-Threading)

📌 Ví dụ: Tạo nhiều Worker để chạy cùng lúc

🔹 main.js (Chạy 3 Worker song song)

const { Worker } = require('worker_threads');

const workers = [];
const numbers = [100000, 500000, 1000000];

for (const num of numbers) {
    const worker = new Worker('./worker.js', { workerData: { num } });

    worker.on('message', (result) => console.log(`✅ Tổng từ 1 đến ${num} là: ${result}`));
    worker.on('error', (err) => console.error(err));
    worker.on('exit', () => console.log(`Worker cho ${num} đã hoàn thành.`));

    workers.push(worker);
}

📌 Kết quả:

✅ Tổng từ 1 đến 100000 là: 5000050000
✅ Tổng từ 1 đến 500000 là: 125000250000
✅ Tổng từ 1 đến 1000000 là: 500000500000
Worker cho 100000 đã hoàn thành.
Worker cho 500000 đã hoàn thành.
Worker cho 1000000 đã hoàn thành.

💡 Lợi ích:

  • Tận dụng tối đa CPU bằng cách chạy nhiều Worker đồng thời.
  • Tăng tốc đáng kể khi xử lý nhiều tác vụ nặng.

🔥 4. Quản lý Worker bằng hàng đợi (Queue)

📌 Vấn đề: Nếu tạo quá nhiều Worker cùng lúc, có thể gây quá tải hệ thống.
📌 Giải pháp: Sử dụng hàng đợi (Queue) để giới hạn số Worker hoạt động đồng thời.

🔹 main.js (Hàng đợi giới hạn 2 Worker cùng lúc)

const { Worker } = require('worker_threads');
const pLimit = require('p-limit');

const MAX_WORKERS = 2; // Giới hạn số Worker đồng thời
const numbers = [100000, 500000, 1000000, 1500000, 2000000];

const limit = pLimit(MAX_WORKERS);

async function runWorker(n) {
    return new Promise((resolve, reject) => {
        const worker = new Worker('./worker.js', { workerData: { num: n } });

        worker.on('message', resolve);
        worker.on('error', reject);
        worker.on('exit', () => console.log(`Worker cho ${n} đã hoàn thành.`));
    });
}

async function processNumbers() {
    const tasks = numbers.map(n => limit(() => runWorker(n)));
    const results = await Promise.all(tasks);
    console.log(`Tổng kết quả: ${results}`);
}

processNumbers();

📌 Kết quả:

  • Luôn chỉ có tối đa 2 Worker chạy cùng lúc, giúp tiết kiệm tài nguyên hệ thống.
  • Khi 1 Worker hoàn thành, ảnh tiếp theo sẽ được xử lý ngay lập tức.

🔥 5. Khi nào KHÔNG nên dùng Worker Threads?

❌ Không cần dùng Worker Threads nếu công việc:

  • I/O-based (đọc ghi file, gọi API, database). Hãy dùng async/await hoặc streaming thay vì Worker Threads.
  • Chỉ xử lý nhanh (dưới 100ms). Không cần tạo Worker vì tốn thêm chi phí khởi tạo.

✅ Nên dùng Worker Threads cho CPU-heavy tasks như:
✔ Xử lý ảnh (Sharp, Puppeteer)
✔ Mã hóa / Giải mã dữ liệu
✔ AI / Machine Learning
✔ Xử lý dữ liệu lớn

🎯 Tóm tắt

✔ Worker Threads giúp tăng tốc xử lý tác vụ nặng mà không làm chậm luồng chính.
✔ Dùng hàng đợi (Queue) để tránh quá tải hệ thống.
✔ Không cần Worker Threads cho các tác vụ I/O-based, hãy dùng async/await.

🚀 Giờ thì bạn có thể tối ưu ứng dụng Node.js bằng Worker Threads một cách chuyên nghiệp!

Để lại một bình luận

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *