<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ workers - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Browse thousands of programming tutorials written by experts. Learn Web Development, Data Science, DevOps, Security, and get developer career advice. ]]>
        </description>
        <link>https://www.freecodecamp.org/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ workers - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Wed, 24 Jun 2026 10:06:06 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/news/tag/workers/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ How to Implement Multi-Threading in Node.js With Worker Threads [Full Handbook] ]]>
                </title>
                <description>
                    <![CDATA[ JavaScript is a single-threaded programming language, and Node.js is the runtime environment for JavaScript. This means that JavaScript essentially runs within Node.js, and all operations are handled through a single thread. But when we perform tasks... ]]>
                </description>
                <link>https://www.freecodecamp.org/news/how-to-implement-multi-threading-in-nodejs-with-worker-threads-full-handbook/</link>
                <guid isPermaLink="false">68fba9c10656b6400beb0762</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                    <category>
                        <![CDATA[ multithreading ]]>
                    </category>
                
                    <category>
                        <![CDATA[ Worker Thread ]]>
                    </category>
                
                    <category>
                        <![CDATA[ workers ]]>
                    </category>
                
                    <category>
                        <![CDATA[ handbook ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Sumit Saha ]]>
                </dc:creator>
                <pubDate>Fri, 24 Oct 2025 16:30:57 +0000</pubDate>
                <media:content url="https://cdn.hashnode.com/res/hashnode/image/upload/v1761323431527/d74eb2ba-edaa-4d19-a041-364e99a705ba.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>JavaScript is a single-threaded programming language, and Node.js is the runtime environment for JavaScript. This means that JavaScript essentially runs within Node.js, and all operations are handled through a single thread.</p>
<p>But when we perform tasks that require heavy processing, Node.js's performance can start to decline. Many people mistakenly think that Node.js isn’t good or that JavaScript is flawed. But there’s actually a solution. JavaScript can also be used effectively with multi-threading.</p>
<p>In this article, we will focus on the backend: specifically, how to implement multi-threading on the server side using Node.js.</p>
<h2 id="heading-heres-what-well-cover"><strong>Here’s What We’ll Cover</strong></h2>
<ol>
<li><p><a class="post-section-overview" href="#heading-prerequisites">Prerequisites</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-project-setup-with-expressjs">Project Setup with ExpressJS</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-1-create-a-new-project-folder">1. Create a New Project Folder</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-2-initialize-a-nodejs-project">2. Initialize a Node.js Project</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-3-install-expressjs">3. Install Express.js</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-4-optional-install-nodemon-for-development">4. Optional: Install Nodemon for Development</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-5-create-the-main-server-file">5. Create the Main Server File</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-6-run-the-project">6. Run the Project</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-the-problem">Understanding the Problem</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-observing-the-behavior">Observing the Behavior</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-why-does-this-happen">Why Does This Happen?</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-understanding-javascript-execution">Understanding JavaScript Execution</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-how-libuv-works">How Libuv Works</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-asynchronous-nature-of-nodejs">Asynchronous Nature of Node.js</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-the-cpu-intensive-problem">The CPU-Intensive Problem</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-worker-threads">How to Implement Worker Threads</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-communication-between-threads">Communication Between Threads</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-setting-up-worker-communication">Setting Up Worker Communication</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-optimize-with-multiple-cores">How to Optimize with Multiple Cores</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-checking-how-many-cores-your-system-has">Checking How Many Cores Your System Has</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-utilizing-multiple-cores-for-faster-execution">Utilizing Multiple Cores for Faster Execution</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-how-to-implement-multi-core-optimization">How to Implement Multi-Core Optimization</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-understanding-the-code-line-by-line">Understanding the Code Line by Line</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-thread-planning-and-configuration">Thread Planning and Configuration</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-dividing-work-across-multiple-workers">Dividing Work Across Multiple Workers</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-handling-complex-tasks">Handling Complex Tasks</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-performance-comparison">Performance Comparison</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-testing-results">Testing Results</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-performance-metrics">Performance Metrics</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-takeaways">Key Takeaways</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-summary">Summary</a></p>
<ul>
<li><p><a class="post-section-overview" href="#heading-the-multi-core-challenge">The Multi-Core Challenge</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-discovering-available-cores">Discovering Available Cores</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-asynchronous-worker-creation">Asynchronous Worker Creation</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-multi-threaded-implementation-strategy">Multi-Threaded Implementation Strategy</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-key-concepts-recap">Key Concepts Recap</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-what-we-learned">What We Learned</a></p>
</li>
</ul>
</li>
<li><p><a class="post-section-overview" href="#heading-final-words">Final Words</a></p>
</li>
<li><p><a class="post-section-overview" href="#heading-additional-resources">Additional Resources</a></p>
</li>
</ol>
<h2 id="heading-prerequisites"><strong>Prerequisites</strong></h2>
<p>To follow along and get the most out of this guide, you should have:</p>
<ol>
<li><p>Basic JavaScript (ES6-style) knowledge</p>
</li>
<li><p>Familiarity with Node.js fundamentals</p>
</li>
<li><p>Web-server basics using Express (or similar)</p>
</li>
<li><p>Understanding of blocking vs non-blocking operations in Node.js / JavaScript</p>
</li>
<li><p>Comfort with asynchronous code (Promises / async/await) and event-based handling</p>
</li>
<li><p>Setting up a simple development environment with Node.js</p>
</li>
</ol>
<p>I’ve also created a video to go along with this article. If you’re the type who likes to learn from video as well as text, you can check it out here:</p>
<div class="embed-wrapper">
        <iframe width="560" height="315" src="https://www.youtube.com/embed/JTl6tQ4bqYA" style="aspect-ratio: 16 / 9; width: 100%; height: auto;" title="YouTube video player" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen="" loading="lazy"></iframe></div>
<p> </p>
<h2 id="heading-project-setup-with-expressjs">Project Setup with ExpressJS</h2>
<p>In this section, we will go through a detailed, beginner-friendly setup for a Node.js project using <a target="_blank" href="https://expressjs.com/">Express</a>. This guide explains every step, so even if you are new to Node.js, you can follow along easily.</p>
<h3 id="heading-1-create-a-new-project-folder">1. Create a New Project Folder</h3>
<p>Start by creating a new folder for your project. Open your terminal or command prompt and run:</p>
<pre><code class="lang-powershell">mkdir node<span class="hljs-literal">-worker</span><span class="hljs-literal">-threads</span>
<span class="hljs-built_in">cd</span> node<span class="hljs-literal">-worker</span><span class="hljs-literal">-threads</span>
</code></pre>
<ul>
<li><p><code>mkdir node-worker-threads</code>: This command creates a new folder named <code>node-worker-threads</code>.</p>
</li>
<li><p><code>cd node-worker-threads</code>: Moves you into the newly created folder where all project files will be stored.</p>
</li>
</ul>
<p>Think of this folder as the home for your project.</p>
<h3 id="heading-2-initialize-a-nodejs-project">2. Initialize a Node.js Project</h3>
<p>Every Node.js project needs a <code>package.json</code> file to manage dependencies and scripts. Run:</p>
<pre><code class="lang-powershell">npm init <span class="hljs-literal">-y</span>
</code></pre>
<ul>
<li><p><code>npm init</code> creates a <code>package.json</code> file.</p>
</li>
<li><p>The <code>-y</code> flag automatically fills in default values, saving you time.</p>
</li>
</ul>
<p>After this, you will see a <code>package.json</code> file in your project folder. This file keeps track of all packages and configurations.</p>
<h3 id="heading-3-install-expressjs">3. Install Express.js</h3>
<p>Express is a lightweight web framework for Node.js. Install it with:</p>
<pre><code class="lang-powershell">npm install express
</code></pre>
<p>This adds Express to your project and allows you to create routes, handle requests, and send responses easily.</p>
<h3 id="heading-4-optional-install-nodemon-for-development">4. Optional: Install Nodemon for Development</h3>
<p>Nodemon automatically restarts your server whenever you make changes. This is very useful during development.</p>
<pre><code class="lang-powershell">npm install <span class="hljs-literal">-D</span> nodemon
</code></pre>
<p>The <code>-D</code> flag installs Nodemon as a development dependency.</p>
<p>Next, Update <code>package.json</code> scripts:</p>
<pre><code class="lang-json">{
  <span class="hljs-attr">"scripts"</span>: {
    <span class="hljs-attr">"dev"</span>: <span class="hljs-string">"nodemon index.js"</span>
  }
}
</code></pre>
<p>Now you can start the server with:</p>
<pre><code class="lang-powershell">npm run dev
</code></pre>
<p>This will automatically restart your server whenever you make code changes.</p>
<h3 id="heading-5-create-the-main-server-file">5. Create the Main Server File</h3>
<p>Create a file called <code>index.js</code>. This will be the main entry point of your application:</p>
<pre><code class="lang-powershell">touch index.js
</code></pre>
<p>Open <code>index.js</code> and add the following code:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js </span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">3000</span>;

<span class="hljs-comment">// Non-blocking route</span>
app.get(<span class="hljs-string">"/non-blocking"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"This page is non-blocking."</span>);
});

<span class="hljs-comment">// Blocking route using Worker Threads</span>
app.get(<span class="hljs-string">"/blocking"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">let</span> result = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000000</span>; i++) {
    result++;
  }
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">`Result is <span class="hljs-subst">${result}</span>`</span>);
});

<span class="hljs-comment">// Start the server</span>
app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`App listening on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>Here’s what’s going on in this code:</p>
<ul>
<li><p><code>express</code>: To create the server.</p>
</li>
<li><p><code>Worker</code>: To run CPU-intensive tasks in a separate thread.</p>
</li>
<li><p><code>/non-blocking</code> route: Sends a quick response immediately.</p>
</li>
<li><p><code>/blocking</code> route: Runs a Worker thread to handle heavy computation.</p>
</li>
<li><p><code>app.listen</code>: Starts the server on port 3000 (or environment port).</p>
</li>
</ul>
<p>Don’t worry if all of this isn’t perfectly clear at the moment. We’ll explore everything in greater detail as we move forward. Get ready, because we’re going to break down each part step by step in the simplest way possible.</p>
<h3 id="heading-6-run-the-project">6. Run the Project</h3>
<p>Start the server using Nodemon:</p>
<pre><code class="lang-powershell">npm run dev
</code></pre>
<p>Or without Nodemon:</p>
<pre><code class="lang-powershell">node index.js
</code></pre>
<p>Visit these URLs in your browser:</p>
<ul>
<li><p><a target="_blank" href="http://localhost:3000/non-blocking"><code>http://localhost:3000/non-blocking</code></a> displays a simple non-blocking message.</p>
</li>
<li><p><a target="_blank" href="http://localhost:3000/blocking"><code>http://localhost:3000/blocking</code></a> executes a CPU-intensive task using Worker Threads.</p>
</li>
</ul>
<p><strong>Congratulations!</strong> Your Node.js project with Express is fully set up and ready for development.</p>
<h2 id="heading-understanding-the-problem">Understanding the Problem</h2>
<p>We have already set up a basic Express.js application, which is essentially a Node.js app. In this application, we have defined <strong>two routes</strong>:</p>
<ol>
<li><p><code>/non-blocking</code></p>
</li>
<li><p><code>/blocking</code></p>
</li>
</ol>
<p>The <code>/non-blocking</code> route is straightforward: it simply returns a text response saying, "This page is non-blocking."</p>
<p>On the other hand, the <code>/blocking</code> route contains a heavy computation. It runs a loop up to one million numbers, calculates the sum of all these numbers, and then returns the result.</p>
<p>Finally, the application is set to run on port 3000 using <code>app.listen</code>.</p>
<h3 id="heading-observing-the-behavior">Observing the Behavior</h3>
<p>If you open your browser and visit the <a target="_blank" href="http://localhost:3000/non-blocking"><code>http://localhost:3000/non-blocking</code></a> URL, it works perfectly fine and responds immediately.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079165626/6d6a3c24-8095-4243-83db-8a44865e5af9.png" alt="Non-blocking Browser" class="image--center mx-auto" width="1920" height="1080" loading="lazy"></p>
<p>But if you visit the <a target="_blank" href="http://localhost:3000/blocking"><code>http://localhost:3000/blocking</code></a> URL, the page keeps loading and doesn’t respond right away.</p>
<p>What's even more interesting is that if you try to access <a target="_blank" href="http://localhost:3000/non-blocking"><code>http://localhost:3000/non-blocking</code></a> <strong>while</strong> <code>/blocking</code> is still running, it also becomes unresponsive.</p>
<p>This demonstrates a key concept: while the <code>/blocking</code> route is executing, even the <code>/non-blocking</code> route cannot respond. In other words, the heavy computation in <code>/blocking</code> <strong>blocks the Node.js event loop</strong>, affecting all other routes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079338040/ecaf458e-d91a-4752-863e-71ac34081949.gif" alt="Blocking Browser" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h3 id="heading-why-does-this-happen">Why Does This Happen?</h3>
<p>The reason lies in how Node.js works. Node.js is essentially a JavaScript runtime, and as we know, JavaScript is a <strong>single-threaded</strong> programming language. Naturally, Node.js also runs on a single thread by default.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079437967/3330b62c-54c2-41a9-bccc-8f962e71287c.gif" alt="Single Threaded Programming" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<p>So, where does the problem arise? When you execute the <code>/blocking</code> route, all the JavaScript code runs on the <strong>main thread</strong>. During this time, the main thread is completely busy or blocked. As a result, if another user tries to access the <code>/non-blocking</code> route, they won't get any response because the main thread is still occupied with the previous task.</p>
<p>This is why many people mistakenly think that JavaScript is weak because it's single-threaded. But this perception is not entirely accurate. With the right approach and techniques, JavaScript <strong>can also be used in a multi-threaded way</strong>, allowing you to handle heavy computations without blocking other operations.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079547228/0799f826-3715-4664-b94b-e8f2e80afd04.gif" alt="Weak JS" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h2 id="heading-understanding-javascript-execution"><strong>Understanding JavaScript Execution</strong></h2>
<p>Let's think about the main thread where JavaScript primarily runs. You might ask, where exactly does JavaScript execute? JavaScript runs inside the <strong>JavaScript engine</strong>, which is responsible for converting JavaScript code into machine code.</p>
<p>In the case of Node.js, it runs on the <strong>V8 engine</strong>, which is the same engine used in Google Chrome. The V8 engine operates entirely on a single thread, meaning all JavaScript code executes within just one main thread.</p>
<p>Now, you might wonder: are there any threads other than the main thread? The answer is yes. Apart from the main thread, there are additional threads used to handle different types of tasks. The management and implementation of these threads are handled by a special library called <strong>Libuv</strong>.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079628895/02bc21f7-1d49-4952-9c17-3f57cbbe3488.gif" alt="Understanding JavaScript Execution" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h3 id="heading-how-libuv-works">How Libuv Works</h3>
<p>Libuv is designed to work alongside the V8 Engine. While the V8 Engine executes JavaScript code on the main thread, additional threads are used to handle different types of tasks. For example, operations like database queries, network requests, or file read/write tasks are handled by these extra threads, and the Libuv library manages and coordinates them.</p>
<p>Whenever we perform such tasks, they are actually executed on these extra threads outside the main thread. Libuv instructs the V8 Engine on how to handle these tasks efficiently. These tasks are commonly referred to as <strong>Input/Output operations</strong>, or I/O operations for short. In other words, when performing file read/write, database queries, or network requests, these I/O operations are executed on separate threads without blocking the Main Thread.</p>
<p>But if we have tasks like a large for-loop in our earlier example, or any operation that primarily requires <strong>CPU processing</strong>, they do not fall under I/O operations. In such cases, the task must be executed on the main thread, which inevitably blocks it until the task is completed.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079720366/9f01e68c-ad5f-491a-9e68-d91a4ec5f3fb.gif" alt="How libuv works" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h3 id="heading-asynchronous-nature-of-nodejs"><strong>Asynchronous Nature of Node.js</strong></h3>
<p>Consider a scenario where a client sends a request to the main thread, and this request requires a database query to be executed.</p>
<p>When the user sends such a request, the database query is sent to the database, but importantly, it <strong>does not block</strong> the main thread. Instead, Libuv handles the database query on a <strong>separate thread</strong>, keeping the Main Thread free to handle other tasks.</p>
<p>In this situation, if another user sends a request that does <strong>not</strong> involve any database query or I/O operation, it can be executed immediately on the Main Thread. As a result, this second user receives a response without any delay.</p>
<p>Once the database query running on the separate thread completes, the result is returned to the Main Thread, which then sends it back as a response to the original user. This approach ensures that users receive their output efficiently, and the main thread remains available for other tasks.</p>
<p>This entire process represents the <strong>asynchronous nature</strong> of JavaScript and Node.js. Tasks are not executed synchronously – instead, they run asynchronously. One user's request can be processed on a separate thread while other users continue to interact with the server seamlessly. This is how Node.js maintains high performance and responsiveness even under multiple simultaneous requests.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079806477/dd7b58e2-48ab-4994-ad09-41fad2f0b78b.gif" alt="Asynchronous Nature of Node.js" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h3 id="heading-the-cpu-intensive-problem"><strong>The CPU-Intensive Problem</strong></h3>
<p>So, this is how everything works effectively. Now, the question is, what happens if the main thread has a task that doesn't require any database access for a user's request but demands heavy CPU processing? In that case, the main thread will get blocked.</p>
<p>Let's say a task on the main thread is consuming a lot of CPU. If we execute it directly on the main thread, the event loop will get blocked, and other requests won't be able to be processed.</p>
<p>This is where <strong>worker threads</strong> come into play in Node.js. With worker threads, we can spin up a new thread outside the main thread to handle CPU-heavy operations separately. As a result, the main thread stays free, allowing other requests to be processed immediately.</p>
<p>In other words, by using worker threads, we can run <strong>CPU-bound</strong> tasks <strong>asynchronously</strong>, ensuring that the server's throughput and responsiveness are not affected.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079890972/98686661-0c5f-493e-a0b4-25c744c60938.gif" alt="CPU Intensive Problem" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h2 id="heading-how-to-implement-worker-threads"><strong>How to Implement Worker Threads</strong></h2>
<p>If we take a look at our previous <code>index.js</code> file, the task in the <code>/blocking</code> route handler is running entirely on the main thread, which is why it causes blocking. So, how can we solve this problem? The solution is to use Node.js's built-in worker threads module.</p>
<p>There is <strong>no need to install any external package</strong>, as worker threads is a core module of Node.js.<br>We can directly require the <code>Worker</code> class from the <code>worker_threads</code> module and create a new worker thread.</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js</span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> { Worker } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"worker_threads"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">3000</span>;

<span class="hljs-comment">// Non-blocking route</span>
app.get(<span class="hljs-string">"/non-blocking"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"This page is non-blocking."</span>);
});

<span class="hljs-comment">// Blocking route using Worker Threads</span>
app.get(<span class="hljs-string">"/blocking"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> worker = <span class="hljs-keyword">new</span> Worker(<span class="hljs-string">"./worker.js"</span>);

  <span class="hljs-keyword">let</span> result = <span class="hljs-number">0</span>;
  <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000000</span>; i++) {
    result++;
  }
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">`Result is <span class="hljs-subst">${result}</span>`</span>);
});

<span class="hljs-comment">// Start the server</span>
app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`App listening on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>How it works:</p>
<ul>
<li><p>Inside the <code>/blocking</code> route handler, we create a new worker using <code>new Worker()</code> and provide a file path.</p>
</li>
<li><p>This file (<code>worker.js</code>) contains the <strong>CPU-heavy</strong> task that we want the worker to execute.</p>
</li>
<li><p>For example, our heavy for-loop is moved into this separate file.</p>
</li>
</ul>
<p>We create a new file named <code>worker.js</code> and paste the loop there:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// worker.js</span>

<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">1000000000</span>; i++) {
  result++;
}
</code></pre>
<p>When we pass the path to <code>worker.js</code> while creating the Worker, Node.js starts a new thread.</p>
<p>This new thread executes the CPU-intensive task independently, keeping the main thread free to handle other incoming requests.</p>
<p>By doing this, the application becomes more responsive and can handle multiple requests without blocking.</p>
<h3 id="heading-communication-between-threads">Communication Between Threads</h3>
<p>In Node.js, we have the main thread and additional worker threads. To coordinate tasks between them, we can use a <strong>messaging system</strong>. Essentially, all results eventually need to reach the main thread. Otherwise, we won't be able to provide any output to the user.</p>
<p>For example, suppose you assign a task to Thread B and another task to Thread C. When these threads complete their tasks, they must inform the main thread. They do this by sending messages through the messaging system.</p>
<p>Think of it like exchanging messages in an inbox: Thread C sends a message directly to the main thread once its task is finished. Through this communication, worker threads notify the main thread about task completion and send any necessary data.</p>
<p>This is exactly the mechanism we will use in our example to handle CPU-heavy tasks with worker threads, ensuring that the main thread remains free and responsive.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761079966779/34f22f5e-9334-4e89-b54f-71de3de90923.gif" alt="Communication between threads" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h3 id="heading-setting-up-worker-communication">Setting Up Worker Communication</h3>
<p>So, we’ve created a <code>worker.js</code> file. Now, the question is, how do we inform the main thread about the task being done in this file?</p>
<p>To achieve this, we extract <code>parentPort</code> from the built-in <code>worker_threads</code> module in Node.js. The <code>parentPort</code> is a special object that allows communication <strong>between the worker thread and the main thread</strong>. It acts as a bridge: whenever the worker completes a task, it can send the result back to the main thread through this channel.</p>
<p>Once the task is complete, we use the method <code>parentPort.postMessage(result)</code> to send the final data. In other words, we’re posting a message to the parent thread, and in our case, that message is the computed result of our loop.</p>
<p>Here’s the full code for the <code>worker.js</code> file:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// worker.js</span>

<span class="hljs-keyword">const</span> { parentPort } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"worker_threads"</span>);

<span class="hljs-keyword">let</span> result = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10000000000</span>; i++) {
  result++;
}

parentPort.postMessage(result);
</code></pre>
<p>In this example:</p>
<ul>
<li><p>We import parentPort from worker_threads.</p>
</li>
<li><p>We perform a heavy task – a loop that counts up to 10 billion.</p>
</li>
<li><p>After finishing the loop, we send the result back to the main thread using <code>parentPort.postMessage(result)</code>.</p>
</li>
</ul>
<p>This is how communication between the worker thread and the main thread takes place in Node.js.</p>
<p>Now, the question is, once we send the data from the worker, how do we <strong>receive it</strong> in the <code>/blocking</code> handler of our <code>index.js</code> file?</p>
<p>To do this, we need to set up a <strong>listener</strong> inside the handler. For that, we use the <code>worker.on()</code> method.</p>
<p>So, what exactly are we listening for? We listen for the <code>"message"</code> event – just like we listen for <code>onClick</code> or other events in JavaScript.</p>
<p>The first parameter of <code>worker.on()</code> is the event name (<code>"message"</code>), and the second parameter is a <strong>callback function</strong>. Inside that callback, the first argument represents the data we receive from the worker.</p>
<p>Once we receive the data, we can send it back to the browser as a response using:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js </span>

<span class="hljs-comment">// Inside the `/blocking` route handler, we listen for messages from the worker thread.</span>
<span class="hljs-comment">// Whenever the worker completes its task and sends a message, </span>
<span class="hljs-comment">// the callback receives the data as the `data` parameter.</span>
<span class="hljs-comment">// We then send this data back to the client as an HTTP response with status code 200.</span>

worker.on(<span class="hljs-string">"message"</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">`Result is <span class="hljs-subst">${data}</span>`</span>);
});
</code></pre>
<p>Explanation<strong>:</strong></p>
<ul>
<li><p><code>worker.on("message", callback)</code> listens for messages sent from the worker thread using <code>parentPort.postMessage()</code>.</p>
</li>
<li><p>The <code>data</code> parameter contains the result sent by the worker.</p>
</li>
<li><p>Using <code>res.status(200).send(...)</code>, we send the computed result back to the browser.</p>
</li>
<li><p>This allows the heavy computation to happen in a separate thread, keeping the main thread free and responsive.</p>
</li>
</ul>
<p>At the same time, we should also handle possible errors.</p>
<p>If any error occurs inside the worker, we can listen for it using the <strong>"error"</strong> event in the same way:</p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js </span>

<span class="hljs-comment">// In the `/blocking` route handler, we listen for any errors that occur inside the worker thread.</span>
<span class="hljs-comment">// If an error occurs, the callback receives the error object `err`,</span>
<span class="hljs-comment">// and we send it back as an HTTP response with status code 400.</span>

worker.on(<span class="hljs-string">"error"</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
  res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">`An Error occurred : <span class="hljs-subst">${err}</span>`</span>);
});
</code></pre>
<p>Explanation<strong>:</strong></p>
<ul>
<li><p><code>worker.on("error", callback)</code> listens specifically for errors inside the worker thread.</p>
</li>
<li><p>The <code>err</code> parameter contains details about what went wrong in the worker.</p>
</li>
<li><p>Using <code>res.status(400).send(...)</code>, we return the error to the client so the request doesn’t hang silently.</p>
</li>
</ul>
<p><strong>Here’s how the complete code looks:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index.js</span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> { Worker } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"worker_threads"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">3000</span>;

<span class="hljs-comment">// Non-blocking route</span>
app.get(<span class="hljs-string">"/non-blocking"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"This page is non-blocking."</span>);
});

<span class="hljs-comment">// Blocking route using worker threads</span>
app.get(<span class="hljs-string">"/blocking"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
  <span class="hljs-keyword">const</span> worker = <span class="hljs-keyword">new</span> Worker(<span class="hljs-string">"./worker.js"</span>);

  worker.on(<span class="hljs-string">"message"</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
    res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">`Result is <span class="hljs-subst">${data}</span>`</span>);
  });

  worker.on(<span class="hljs-string">"error"</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
    res.status(<span class="hljs-number">400</span>).send(<span class="hljs-string">`An Error occured : <span class="hljs-subst">${err}</span>`</span>);
  });
});

<span class="hljs-comment">// Start the server</span>
app.listen(port, <span class="hljs-function">() =&gt;</span> {
  <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`App listening on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>Once this is set up, you'll see a dramatic change. The <code>/blocking</code> route is loading, but even while it's loading, repeatedly refreshing the <code>/non-blocking</code> route works perfectly without any issues!</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761080061445/f1f213c7-6cce-4334-81e5-8cd828682f8e.gif" alt="Setting up worker communication" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<p>Now notice, the <code>/non-blocking</code> route is accessible, which means even though the <code>/blocking</code> route is still running, it doesn't affect anything. So, we've successfully solved this problem. We moved the main task to a separate thread outside the main thread. What does this mean? The main thread created a new worker thread and assigned the CPU-heavy task to it. The new thread now works independently, while the main thread remains free.</p>
<p>Finally, when the new thread completes its task, it also becomes free. Then, through the messaging system, the new thread informs the main thread, "Your data is ready, here's your data." The main thread receives this data and sends it to the client as a response.</p>
<p>Therefore, the tasks that were automatically handled on separate threads for database queries or file read-write operations – because they were I/O operations – we have now manually initiated a thread and used it to handle similar CPU-heavy tasks.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761080131679/148cc279-e4f0-4f68-b2a9-34110abcbc90.gif" alt="IO Operations" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h2 id="heading-how-to-optimize-with-multiple-cores">How to Optimize with Multiple Cores</h2>
<p>Now that you have a clear understanding of how the process works, let's take it one step further and optimize it using multiple CPU cores.</p>
<p>When you visit the <code>/blocking</code> route, you might notice that it still takes a significant amount of time to respond. This indicates that the optimization isn't fully complete yet. So far, we've used a separate thread meaning we've utilized <strong>one CPU core</strong> outside the main thread. But most modern machines have <strong>multiple cores</strong>, and we can take advantage of that to improve performance.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761080243361/dddd924c-9138-4790-ac6c-811b39772c6c.gif" alt="Final index" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h3 id="heading-checking-how-many-cores-your-system-has">Checking How Many Cores Your System Has</h3>
<p>Before assigning multiple cores, you can check how many cores are available on your system:</p>
<ul>
<li><p><strong>macOS (Unix-based):</strong></p>
<pre><code class="lang-powershell">  sysctl <span class="hljs-literal">-n</span> hw.ncpu
</code></pre>
<p>  This command returns the total number of CPU cores on your machine. For example, on my Mac, it shows <code>10</code>, meaning I have ten cores available.</p>
</li>
<li><p><strong>Linux:</strong></p>
<pre><code class="lang-powershell">  nproc
</code></pre>
<p>  This will print the number of processing units available.</p>
</li>
<li><p><strong>Windows (Command Prompt):</strong></p>
<pre><code class="lang-powershell">  <span class="hljs-built_in">echo</span> %NUMBER_OF_PROCESSORS%
</code></pre>
</li>
</ul>
<p>Each of these commands will help you determine how many cores you can use for parallel processing.</p>
<h3 id="heading-utilizing-multiple-cores-for-faster-execution">Utilizing Multiple Cores for Faster Execution</h3>
<p>Once you know how many cores your machine has, you can decide how many of them to allocate for a specific job. For example, since my system has ten cores, I might choose to use four cores for the task.</p>
<p>By distributing the workload across multiple threads (each running on its own core), you can achieve significant performance improvements. Instead of relying on just one core, the system can execute multiple parts of the task simultaneously reducing the total execution time dramatically.</p>
<p>In short, the more cores you effectively utilize, the faster your computationally heavy tasks can complete (as long as your code is designed to handle parallel execution safely).</p>
<h2 id="heading-how-to-implement-multi-core-optimization">How to Implement Multi-Core Optimization</h2>
<p>Now, we'll optimize the <code>/blocking</code> task by using multiple worker threads. First, we’ll create copies of our existing files:</p>
<ul>
<li><p><code>index.js</code> → <code>index-optimized.js</code></p>
</li>
<li><p><code>worker.js</code> → <code>worker-optimized.js</code></p>
</li>
</ul>
<p>We plan to use four threads. Even though the machine may have more cores, using all could overload the system, so we’ll limit it to four.</p>
<p><strong>index-optimize.js:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// index-optimize.js</span>

<span class="hljs-keyword">const</span> express = <span class="hljs-built_in">require</span>(<span class="hljs-string">"express"</span>);
<span class="hljs-keyword">const</span> { Worker } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"worker_threads"</span>);

<span class="hljs-keyword">const</span> app = express();
<span class="hljs-keyword">const</span> port = process.env.PORT || <span class="hljs-number">3000</span>;
<span class="hljs-keyword">const</span> THREAD_COUNT = <span class="hljs-number">4</span>;

<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">createWorker</span>(<span class="hljs-params"></span>) </span>{
    <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> <span class="hljs-built_in">Promise</span>(<span class="hljs-function">(<span class="hljs-params">resolve, reject</span>) =&gt;</span> {
        <span class="hljs-keyword">const</span> worker = <span class="hljs-keyword">new</span> Worker(<span class="hljs-string">"./worker-optimized.js"</span>, {
            <span class="hljs-attr">workerData</span>: {
                <span class="hljs-attr">thread_count</span>: THREAD_COUNT,
            },
        });

        worker.on(<span class="hljs-string">"message"</span>, <span class="hljs-function">(<span class="hljs-params">data</span>) =&gt;</span> {
            resolve(data);
        });

        worker.on(<span class="hljs-string">"error"</span>, <span class="hljs-function">(<span class="hljs-params">err</span>) =&gt;</span> {
            reject(<span class="hljs-string">`An Error occured : <span class="hljs-subst">${err}</span>`</span>);
        });
    });
}

app.get(<span class="hljs-string">"/non-blocking"</span>, <span class="hljs-function">(<span class="hljs-params">req, res</span>) =&gt;</span> {
    res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">"This page is non-blocking."</span>);
});

app.get(<span class="hljs-string">"/blocking"</span>, <span class="hljs-keyword">async</span> (req, res) =&gt; {
    <span class="hljs-keyword">const</span> workerPromise = [];

    <span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; THREAD_COUNT; i++) {
        workerPromise.push(createWorker());
    }

    <span class="hljs-keyword">const</span> threadResults = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(workerPromise);
    <span class="hljs-keyword">const</span> total =
        threadResults[<span class="hljs-number">0</span>] +
        threadResults[<span class="hljs-number">1</span>] +
        threadResults[<span class="hljs-number">2</span>] +
        threadResults[<span class="hljs-number">3</span>];

    res.status(<span class="hljs-number">200</span>).send(<span class="hljs-string">`Result is <span class="hljs-subst">${total}</span>`</span>);
});

app.listen(port, <span class="hljs-function">() =&gt;</span> {
    <span class="hljs-built_in">console</span>.log(<span class="hljs-string">`App listening on port <span class="hljs-subst">${port}</span>`</span>);
});
</code></pre>
<p>Here, we create a <code>createWorker</code> function that returns a Promise. Inside it, the worker is created, and the message and error events are handled. In the <code>/blocking</code> route, we create multiple workers asynchronously, wait for all of them to finish using <code>Promise.all</code>, and then sum the results.</p>
<p><strong>worker-optimize.js:</strong></p>
<pre><code class="lang-javascript"><span class="hljs-comment">// worker-optimize.js</span>

<span class="hljs-keyword">const</span> { parentPort, workerData } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"worker_threads"</span>);

<span class="hljs-keyword">let</span> result = <span class="hljs-number">0</span>;
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">let</span> i = <span class="hljs-number">0</span>; i &lt; <span class="hljs-number">10000000000</span> / workerData.thread_count; i++) {
    result++;
}

parentPort.postMessage(result);
</code></pre>
<p>Each worker receives <code>thread_count</code> from the main thread and calculates its part of the task. Once done, it sends the result back using <code>parentPort.postMessage</code>. This way, heavy computation is distributed, and the main thread remains free.</p>
<h3 id="heading-understanding-the-code-line-by-line">Understanding the Code Line by Line</h3>
<p>Alright, some of these concepts might seem a bit complex at first. But don't worry! We we’ll go through all the code line by line, explaining everything in detail so that you understand exactly what is happening and why.</p>
<h3 id="heading-thread-planning-and-configuration">Thread Planning and Configuration</h3>
<p>Now, coming to the main point we'll be using threads, right? We've planned to use multiple threads. Let's say we've decided to use four threads. Our machine has ten cores, but we won't use them all because that would consume all our system resources. So, we'll use four threads from four of the available cores.</p>
<p>For this reason, in the <code>index-optimized.js</code> file, we've created a constant to store the number of threads we'll use. Let's say we've set it to 4 here, so that later another developer can easily change it if needed.</p>
<h4 id="heading-the-createworker-function">The createWorker Function</h4>
<p>Then, we've created a new function called <code>createWorker</code>. The purpose of this function is to create a new Worker. Here, we’re returning a promise because the process of creating a Worker is performed asynchronously.</p>
<p>This is because when we create four workers, we want the creation process itself to happen asynchronously, so the main thread doesn't get blocked. After all, creating a worker is essentially a separate process.</p>
<p>The best practice is to create workers asynchronously. That's why we created the <code>createWorker</code> function, which returns a promise. As we know, events are listened to inside a promise, where resolve and reject are used. In the <code>/blocking</code> handler, we can handle the worker's result or any errors through this promise.</p>
<h4 id="heading-creating-a-worker">Creating a Worker</h4>
<p>To create a worker, we use:</p>
<pre><code class="lang-javascript"><span class="hljs-keyword">const</span> worker = <span class="hljs-keyword">new</span> Worker(<span class="hljs-string">"./worker-optimized.js"</span>);
</code></pre>
<p>Here, we need to provide the path to the Worker file. Then, as the second parameter, we can pass some options. For example, if we want to send some data to the Worker, we use <code>{ workerData }</code>. Inside this <code>workerData</code>, we'll send the <code>THREAD_COUNT</code>, which is stored in our file as <code>THREAD_COUNT</code>.</p>
<p>For instance, we can pass an object in <code>workerData</code> like:</p>
<pre><code class="lang-javascript">{
  <span class="hljs-attr">threadCount</span>: THREAD_COUNT;
}
</code></pre>
<p>When this Worker is being created, we send some properties from <code>index-optimized.js</code> as <code>workerData</code>. This is because in <code>worker-optimized.js</code>, the worker can use <code>parentPort</code> to know how many threads it should use. So, we've included a <code>threadCount</code> property in <code>workerData</code>. When the worker starts, it reads <code>threadCount</code> from <code>workerData</code> and works accordingly. This is how we've designed the <code>createWorker</code> function, which simply returns a Promise.</p>
<h4 id="heading-event-handling-and-promise-structure">Event Handling and Promise Structure</h4>
<p>Here, we made an important change compared to our original <code>index.js</code> file.</p>
<p>Since we copied all the code from <code>index.js</code> into <code>index-optimized.js</code>, we adjusted the <code>/blocking</code> route handler. Specifically, we removed the direct creation of the Worker from the <code>/blocking</code> handler. Instead, the Worker is now created inside the <code>createWorker</code> function.</p>
<p>Also, all the event listeners (<code>message</code> and <code>error</code>) that were previously inside the <code>/blocking</code> handler have also been moved into the <code>createWorker</code> function. This means that the worker is fully managed within the function, and the <code>/blocking</code> handler now only handles the promise results, keeping the main thread clean and organized.</p>
<p>But since these events are being listened to inside a promise, we cannot send the response directly from there. We'll send the response inside the <code>/blocking</code> handler. So from the Promise, we only use <code>resolve</code> and <code>reject</code>.</p>
<p><strong>For example:</strong></p>
<pre><code class="lang-javascript">resolve(<span class="hljs-string">`Result is <span class="hljs-subst">${data}</span>`</span>);
reject(<span class="hljs-string">`An error occurred <span class="hljs-subst">${err}</span>`</span>);
</code></pre>
<p>In other words, the entire process of creating a worker has been moved into the <code>createWorker</code> function, which ultimately returns a promise.</p>
<h3 id="heading-dividing-work-across-multiple-workers">Dividing Work Across Multiple Workers</h3>
<p>Now, inside the <code>/blocking</code> handler, I simply call the <code>createWorker</code> function. The workerData we provide tells the worker what task it should perform. The created worker is linked with parentPort in the <code>worker-optimized.js</code> file, which essentially communicates with the parent thread.</p>
<p>Now, we want to divide the for-loop running up to one million across four cores. The number of cores to use is sent from <code>index-optimized.js</code> as part of workerData. Because this information is in workerData, the workers can automatically divide and handle the tasks among themselves.</p>
<p>So, in the <code>worker-optimized.js</code> file, we'll get the workerData using:</p>
<pre><code class="lang-javascript">{ workerData } = <span class="hljs-built_in">require</span>(<span class="hljs-string">"worker_threads"</span>)
</code></pre>
<p>Then, in the for-loop condition, we'll use <code>workerData.threadCount</code>. This means the threadCount sent from <code>index-optimized.js</code> will be used here instead of hardcoding 4. This is best practice because the data is passed to the worker at the time of its creation. In <code>worker-optimized.js</code>, we use this to divide the work into four parts. Then, four workers will be created, meaning the <code>createWorker</code> function will be called four times. Each worker will take one part of the work, and at the end, all results will be combined. This is how the entire process is completed.</p>
<p>So, in this <code>/blocking</code> handler, our task is to collect the results of the four promises and then sum them all. Let's say we store them in an array called <code>workerPromises</code>. Each entry in this array will hold the promise result of a worker. Then, by combining all of them, we get the final result.</p>
<p>Since we need to create four Workers, we'll run a for-loop: <code>for (let i = 0; i &lt; THREAD_COUNT; i++)</code>. Inside the body of this loop, we'll call the <code>createWorker</code> function each time. This means that in every iteration, a new worker is created, and its promise is pushed into the <code>workerPromises</code> array.</p>
<p>So, inside the body of this loop, we'll call the <code>createWorker</code> function four times. Each call to <code>createWorker</code> returns a promise. These four promises are pushed into the <code>workerPromises</code> array, like <code>workerPromises.push(createWorker())</code>. This way, each worker has its own promise. In the end, since all the promises are stored in the <code>workerPromises</code> array, we can easily call <code>Promise.all(workerPromises)</code>.</p>
<p>So, we used <code>threadResults = await Promise.all(workerPromises)</code>. As we know, <code>Promise.all</code> can handle multiple Promises together. Here, we passed the <code>workerPromises</code> array, so <code>threadResults</code> will contain the results of the four promises as separate elements, like <code>threadResults[0]</code>, <code>threadResults[1]</code>, <code>threadResults[2]</code>, and <code>threadResults[3]</code>. Then, we sum these results to get the total calculation, meaning <code>threadResults[0] + threadResults[1] + threadResults[2] + threadResults[3]</code> gives the final result. Since we used await, the entire function needs to be async.</p>
<p>Once everything is done correctly, we can send this total result to the client using <code>res.status(200).send(Result is ${total})</code>. This way, the total calculation works correctly, unlike before.</p>
<p>So, I hope it's clear now: we called the <code>createWorker</code> function four times here. Each call returns a promise. We then awaited all these promises together using <code>Promise.all</code>, so all the results came in at once. After that, we summed these results. The <code>/blocking</code> handler is essentially the one executing our operational work.</p>
<h3 id="heading-handling-complex-tasks">Handling Complex Tasks</h3>
<p>So, in the <code>worker-optimized.js</code> file, we've essentially divided the work into four parts. But it's not necessary that the task will always be a for-loop. There could be different types of complex tasks as well, like image processing, data processing, or pagination.</p>
<p>In such cases, we can't always follow the same pattern. So, we need to send the necessary data from <code>index-optimized.js</code> as <code>workerData</code>, and the worker will use that data to perform the task in a separate process.</p>
<p>In the previous example, all the steps were sequential, so simply summing the results gave us the total. But in the case of complex tasks, we need to use data-driven processing.</p>
<p>In other complex applications, you might need to perform different tasks. But the main concept is clear: any data or property we send from here will be received by the worker, which will then divide the work. Each worker – whether you use four, five, or six – will handle its part, and all the results will need to be accumulated. This is essentially the entire process.</p>
<h2 id="heading-performance-comparison"><strong>Performance Comparison</strong></h2>
<p>When working with CPU-intensive tasks in Node.js, dividing the work using worker threads can significantly improve performance. Let's compare the behavior of our application before and after optimization.</p>
<h3 id="heading-testing-results">Testing Results</h3>
<p>Running the <code>index.js</code> file and hitting the <code>/blocking</code> route in the browser takes a significant amount of time.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761164273474/02892dd3-3524-4e7e-83fa-ac279910d759.gif" alt="Final Index" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<p>Running the <code>index-optimized.js</code> file and hitting the same route takes considerably less time – around 3 seconds.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761164303764/4ba27180-49f7-4485-a1a5-73f2f419ab9b.gif" alt="Final Optimized" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<p>Stopping it and running <code>index.js</code> again clearly shows the original implementation is slower.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1761164358090/4c3b9056-b936-4341-9302-461c290ea70e.gif" alt="Final unoptimized" class="image--center mx-auto" width="1138" height="640" loading="lazy"></p>
<h3 id="heading-performance-metrics">Performance Metrics</h3>
<div class="hn-table">
<table>
<thead>
<tr>
<td><strong>File</strong></td><td><strong>Route</strong></td><td><strong>Approx. Response Time</strong></td><td><strong>Notes</strong></td></tr>
</thead>
<tbody>
<tr>
<td><code>index.js</code></td><td><code>/blocking</code></td><td>Much longer</td><td>This is the original implementation. The single-threaded loop blocks the event loop, causing delays.</td></tr>
<tr>
<td><code>index-optimized.js</code></td><td><code>/blocking</code></td><td>Around 3 seconds</td><td>Here, the work is divided into multiple worker threads, making the process much faster.</td></tr>
</tbody>
</table>
</div><h3 id="heading-key-takeaways">Key Takeaways</h3>
<p>This comparison demonstrates how dividing the work into multiple parts using worker threads can make CPU-intensive tasks far more efficient, keeping the main thread responsive and improving overall performance.</p>
<h2 id="heading-summary">Summary</h2>
<p>So, first we saw in <code>index.js</code> how a blocking task can be handled in a <code>non-blocking</code>, asynchronous way. That is, we ran a worker thread, and because of this worker thread, the main thread didn't get blocked, allowing other users to continue their tasks simultaneously.</p>
<h3 id="heading-the-multi-core-challenge">The Multi-Core Challenge</h3>
<p>But the problem is, when we use a new thread on the server, there isn't just a single core. Usually, there are multiple cores, like <code>8</code>, <code>16</code>, or more. To use multiple cores, we first need to find out how many cores are available on the server.</p>
<h3 id="heading-discovering-available-cores">Discovering Available Cores</h3>
<p>If the server is Linux, we can easily find out the total number of cores using the <code>nproc</code> command. Then we can decide how many cores to use. For example, let's say we decide to use three cores. In <code>index-optimized.js</code>, we've implemented a way to divide the work among these cores.</p>
<h3 id="heading-asynchronous-worker-creation">Asynchronous Worker Creation</h3>
<p>So, what we did was wrap the worker creation process in a promise. Since creating a worker takes some time and spinning it up isn't instantaneous, this process is done asynchronously. This way, even if multiple users hit the endpoint to create Workers, the main thread won't be blocked.</p>
<h3 id="heading-how-to-implement-multi-core-optimization-1">How to Implement Multi-Core Optimization</h3>
<p>We simply created workers, and then using the <code>createWorker</code> function inside a loop, we spawned four or a specified number of Workers based on the thread count. Each worker posts messages independently, and through the listener, we receive data from each worker. These results are collected via promises, stored together in an array, and finally, we sum all the results from this array to get the final outcome.</p>
<p>So, the other concepts are all part of basic JavaScript. I hope you now understand how worker threads work and how we can use multi-threaded processes in Node.js. It's an excellent concept and a great opportunity to learn thoroughly.</p>
<h3 id="heading-what-we-learned"><strong>What We Learned</strong></h3>
<p>Worker Threads in Node.js provide a powerful way to handle CPU-intensive tasks without blocking the main event loop. By leveraging multiple cores and distributing work across threads, we can significantly improve application performance while maintaining responsiveness for other users.</p>
<ul>
<li><p><strong>Non-blocking execution</strong>: Worker threads prevent the main thread from being blocked</p>
</li>
<li><p><strong>Multi-core utilization</strong>: We can leverage multiple CPU cores for parallel processing</p>
</li>
<li><p><strong>Asynchronous worker creation</strong>: Using promises to handle worker creation without blocking</p>
</li>
<li><p><strong>Result aggregation</strong>: Collecting and combining results from multiple workers</p>
</li>
<li><p><strong>Performance optimization</strong>: Distributing heavy computations across multiple threads</p>
</li>
</ul>
<p>This approach is particularly valuable for applications that need to handle computationally intensive tasks while remaining responsive to user requests.</p>
<h2 id="heading-final-words">Final Words</h2>
<p>If you found the information here valuable, feel free to share it with others who might benefit from it. I’d really appreciate your thoughts – mention me on X <a target="_blank" href="https://x.com/sumit_analyzen">@sumit_analyzen</a> or on Facebook <a target="_blank" href="https://facebook.com/sumit.analyzen">@sumit.analyzen</a>, <a target="_blank" href="https://youtube.com/@logicBaseLabs">watch my coding tutorials</a>, <a target="_blank" href="https://sumitsaha.me">visit my website</a> or simply <a target="_blank" href="https://www.linkedin.com/in/sumitanalyzen/">connect with me</a> on LinkedIn.</p>
<h2 id="heading-additional-resources">Additional Resources</h2>
<p>You can also check the <a target="_blank" href="https://nodejs.org/api/worker_threads.html">Node.js Worker Threads documentation</a> for more in-depth learning. You can find all the source code from this tutorial in <a target="_blank" href="https://github.com/logicbaselabs/node-worker-threads/">this GitHub repository</a>. If it helped you in any way, consider giving it a star to show your support!</p>
 ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
