Using Worker Threads in Node.js
Welcome back! Let's dive into how we can use worker threads in Node.js to perform parallel operations efficiently.
Setting Up Worker Threads
Step 1: Create a Worker Threads Example File
Start by creating a folder, ThreadsExample
, and within it, create a file called threads-dogs.js
.
Step 2: Importing the Worker Threads Module
To use worker threads, require the worker_threads
module and destructure the necessary values from it:
const { Worker, isMainThread, workerData } = require('worker_threads');
Step 3: Checking the Execution Context
The isMainThread
value helps us determine if the current code is running in the main thread or a worker thread. Using this, we can create new worker threads conditionally:
if (isMainThread) {
console.log(`Main thread has process ID: ${process.pid}`);
// Creating two worker threads
new Worker(__filename, { workerData: [7, 6, 2, 3] });
new Worker(__filename, { workerData: [1, 3, 4, 3] });
} else {
console.log(`Worker thread has process ID: ${process.pid}`);
}
Here, __filename
is a Node.js global variable that refers to the current file path. We pass it to the Worker
constructor so that each worker runs the code within the same file.
Step 4: Avoid Infinite Worker Creation
To prevent recursive worker creation, ensure new workers are created only in the main thread by checking isMainThread
.
Demonstrating Shared Process ID
Unlike the cluster
module, which spawns separate processes, worker threads run within the same process. To see this:
if (isMainThread) {
console.log(`Main thread has process ID: ${process.pid}`);
new Worker(__filename, { workerData: [7, 6, 2, 3] });
new Worker(__filename, { workerData: [1, 3, 4, 3] });
} else {
console.log(`Worker thread has process ID: ${process.pid}`);
}
Running this code will output identical process IDs for the main thread and all worker threads.
Performing Parallel Operations
Now let's assign some work to the worker threads. Suppose we have arrays of numbers to sort. Sorting is a CPU-intensive operation, which makes it a great use case for worker threads.
Passing Data to Worker Threads
The Worker
constructor accepts an object as a second parameter, where the workerData
property allows us to send data to the worker:
if (isMainThread) {
new Worker(__filename, { workerData: [7, 6, 2, 3] });
new Worker(__filename, { workerData: [1, 3, 4, 3] });
} else {
console.log(`Worker data: ${workerData}`);
// Sorting the array
const sortedData = workerData.sort((a, b) => a - b);
console.log(`Sorted data: ${sortedData}`);
}
Output
When you run the program using node threads-dogs.js
, you’ll see output like this:
Main thread has process ID: 12345
Worker data: [7, 6, 2, 3]
Sorted data: [2, 3, 6, 7]
Worker data: [1, 3, 4, 3]
Sorted data: [1, 3, 3, 4]
Explanation
The main thread sends an array to each worker thread using
workerData
.Each worker processes the data independently by sorting the array.
The sorted arrays are logged to the console.
Key Advantages
Parallel Execution: Each worker thread runs independently, taking advantage of multiple CPU cores.
Shared Memory: All threads share the same process memory, reducing overhead compared to spawning separate processes.
Efficient Resource Utilization: Worker threads provide a more efficient alternative to clustering for non-server-related tasks.
Summary
Using worker threads in Node.js allows us to execute JavaScript in parallel, optimizing CPU-bound tasks. While they’re not a replacement for clusters in server scenarios, worker threads are perfect for tasks like sorting, data processing, and mathematical computations.