Worker Threads enable true parallelism in Node.js, perfect for CPU-intensive tasks. Let's dive in.
Why Worker Threads?
- Parallel execution of JavaScript code
- Shared memory capabilities
- Ideal for CPU-bound operations
Basic Usage
const { Worker, isMainThread, parentPort } = require('worker_threads');
if (isMainThread) {
const worker = new Worker(__filename);
worker.on('message', (msg) => console.log('From worker:', msg));
worker.postMessage('Hello, Worker!');
} else {
parentPort.on('message', (msg) => {
console.log('From main:', msg);
parentPort.postMessage('Hello, Main!');
});
}
Passing Data
- Structured Clone Algorithm (default)
- Transferable objects
- SharedArrayBuffer for zero-copy transfers
const { Worker } = require('worker_threads');
const worker = new Worker('./worker.js');
const sharedBuffer = new SharedArrayBuffer(4);
const arr = new Int32Array(sharedBuffer);
arr[0] = 123;
worker.postMessage({ sharedBuffer });
Worker Pools
const { StaticPool } = require('node-worker-threads-pool');
const pool = new StaticPool({
size: 4,
task: (n) => n * 2
});
async function runTasks() {
const results = await Promise.all([
pool.exec(10),
pool.exec(20),
pool.exec(30)
]);
console.log(results); // [20, 40, 60]
}
runTasks().catch(console.error);
Best Practices
- Use for CPU-intensive tasks, not I/O operations
- Implement proper error handling
- Carefully manage shared resources to avoid race conditions
- Consider using worker pools for better resource management
Performance Considerations
- Thread creation has overhead; reuse workers when possible
- Balance number of workers with available CPU cores
- Minimize data transfer between threads
Pitfalls to Avoid
- Overusing for simple tasks (threading has overhead)
- Neglecting to terminate workers when done
- Assuming automatic load balancing (you must manage this)
Worker Threads shine for parallel processing of CPU-intensive tasks. Use wisely to supercharge your Node.js applications.
Cheers🥂