Your manager is shouting at you to improve your Node js performance but you are stuck. You either want to quit your job or hit your manager's head with a brick. Please don't do either. In this post I am going to tell you how you can improve your Nodejs application performance.
If you are lazy to read, i also have video for same topic.
Application's performance has always been a challenge for any developer in any programming language.You can define a good developer as a developer who can develop most efficient or best performing applications and in case of web development applications, the more number of I/O the application can handle, the better performant is the application.So we have to build applications which can handle a lot of i/o smoothly and without any delay.
First let's try to understand the potential reason for the lag or the inefficiency. As we know behind the scenes Node js has this awesome event loop which helps nodejs to run multiple tasks at once very smoothly, so how exactly node js slows down.
If we dive deep in event loop phases we see that the poll phase can be the reason for slowness sometimes if the I/O is too big to be executed. Yeah it's possible that if we do some CPU intensive work, the poll phase may take more time and your whole application slows down. It is not a big deal. Large scale applications sometimes face this issue. So let's talk about how we can handle these scenarios in node JS applications.
The best solution which I always recommend and I also personally use is using "Worker thread". Yeah I know that Node JS is a single threaded framework, so we are not going to actually use multithreading over here. Instead of that we are going to spin up some worker threads which will be running on a separate event loop. This new event loop will be completely isolated from the main event loop and any kind of CPU intensive work we are going to offload to this thread. Now let's try to take an example where we can create a new worker thread and we'll try to understand how you can implement the same in your application.Same implementation I have already done in of one of my YouTube videos, so, if you are a video kind of person then you can check out my video on my YouTube channel.
Let's talk about the example, we are going to create a main script where our main thread will be running and we are going to create another script where we are going to do some CPU intensive work and then we are going to run this separate script in a separate worker thread. Let's start step by step how we can create a worker thread and how we can offload our work to that thread.
We will create a main.js in which I am going to listen to a single API and also we are going to create a separate module in which we are going to do do a CPU intensive work which will be calculating a Factorial of a given number as we all know calculating factorials takes up a lot of CPU.
const express = require('express');
const http = require('http');
async function init() {
const port = process.env.PORT;
const app = express();
const httpsServer = http.Server(app);
app.get('/', (req, res, next) => {
//do stuffs
res.json({ message: "All good" })
});
httpsServer.listen(port, () => {
logger.info(`App listening on port ${port}`);
});
}
init();
Lets create a module for factorial
module.exports = (number) => {
const getFactorial = (number) => {
if (number === 1) return 1
return number * getFactorial(number - 1);
}
return getFactorial(number);
}
Now the traditional method is we import factorial js in main js and use it in the api response
const getFactorial = require('./factorial');
app.get('/', (req, res, next) => {
const number = req.query.number;
res.json({ message: "All good" });
});
In this case when numbers are bigger, the process will take up time and block other processes, and that's what we don't want. So we will create a worker thread.
Lets create a new worker thread and do calculations in that, creating a worker is simple, You have to create a separate file for the worker and use that file to create a worker instance in any file.
const { Worker } = require('worker_threads');
const worker = new Worker('myworkerthread.js');
Your worker file will be simple script where direct logic will be written.
const getFactorial = (number) => {
if (number === 1) return 1
return number * getFactorial(number - 1);
}
getFactorial(number);
Now if we want to share data between this worker thread and the main thread, we can share data by emitting messages.
To emit messages to worker thread from parent thread
worker.postMessage(message);
To emit messages to parent thread from worker thread
const { parentPort } = require('worker_threads');
parentPort.postMessage(message);
You have to listen for parent Messages in the worker thread and for worker messages in parent thread. We have dedicated ports to listen to these emitted messages.
To listen worker message in parent thread
worker.on('message', (message) => {
console.log("Worker Message", message);
});
To listen parent message in worker thread
const { parentPort } = require('worker_threads');
parentPort.on('message', (message) => {
console.log("Parent Message", message);
});
Finally your main.js will look like
const express = require('express');
const http = require('http');
const { Worker } = require('worker_threads');
async function init() {
const port = process.env.PORT;
const app = express();
const factorialworker = new Worker('./factorial.js');
const httpsServer = http.Server(app);
app.get('/', (req, res, next) => {
const number = req.query.number;
factorialworker.postMessage(number);
res.json({ message: "All good" });
});
factorialworker.on('message', (data) => {
console.log("Here is your factorial", data);
})
httpsServer.listen(port, () => {
logger.info(`App listening on port ${port}`);
});
}
init();
And you factorial.js will be
const { parentPort } = require('worker_threads')
const getFactorial = (number) => {
if (number === 1) return 1
return number * getFactorial(number - 1);
}
parentPort.on('message', (number) => {
parentPort.postMessage(getFactorial(number))
});
Git REpo for Code: https://github.com/shaikh-kamran/nodejs-worker-thread-example
Hope this blog helps you understand the implementation of worker thread in Node js application,
Happy Koding everyone!!!
Top comments (0)