Node JS : Single or Multi Threaded ?

Node JS : Single or Multi Threaded ?

Let me not bore you, this is going to be a short long normal blog post.

Question : Is Node JS single threaded or multithreaded ? Short Answer: Node JS is Single Threaded

Long answer: Allow me explain the concepts...

I'll be using one of the node js internal library to explain this concept, the library I will be using is called Libuv, and then we will see how the Crypto module multi-threads in node js.

Consider the code below:

With the popular fact that node js is single threaded, each encryption will run after the first one finishes, but that's not the case with every node js module, some module multithreads using the Libuv thread pool.

const crypto = require('crypto');

crypto.pbkdf2('a','b',100000, 512,'sha512',()=>{
    console.log('1:',Date.now() - start)
})

crypto.pbkdf2('a','b',100000, 512,'sha512',()=>{
    console.log('2:',Date.now() - start)
})

crypto.pbkdf2('a','b',100000, 512,'sha512',()=>{
    console.log('3:',Date.now() - start)
})

crypto.pbkdf2('a','b',100000, 512,'sha512',()=>{
    console.log('4:',Date.now() - start)
})

The result of this code above is in the image below

Screen Shot 2021-04-11 at 2.48.46 PM.png

Now, from the image above, it shows that hashing 1, 2, 3 and 4 ran at same time, and 5 ran later, if Node JS was single threaded, the hashes will run one after the other. Now why didn't all 5 run at same time ? The libuv creates 4 thread pool as default, and this can be increased by adding process.env.UV_THREADPOOL_SIZE = 5; at the top of our code. This will make all 5 hashes be assigned to 5 different thread pool and they'll complete at the-same time.

If that's not clear, let me use RACE CONDITION to explain that node JS is multithreaded.

What is Race Condition ? Race condition is when two or more threads are seeking permission to access to access shared resources and try to change it at same time, because the OS scheduler can swap access to a shared resource at any given time, therefore, the result of the change in data is dependent on the thread scheduling algorithm, i.e. both threads are "racing" to access/change the data.

Consider the code below:

const fs = require('fs');
const fileName = __dirname + '/test.txt';

console.log("Starting...");

// Read async
fs.readFile(fileName, 'utf8', function(err, data) {
    if(err)
        console.log("first read returned error: ", err);
    else {
        if (data === null) 
            console.log("first read returned NULL data!");
        else if (data === "") 
            console.log("first read returned EMPTY data!");
        else
            console.log("first read returned data: ", data);
    }
});


// Write async
fs.writeFile(fileName, 'updated text', 'utf8', function(err) {
    if(err)
        console.log("write finished with error: ", err);
    else
        console.log("write finished OK");
});


// Read async
fs.readFile(fileName, 'utf8', function(err, data) {
    if(err)
        console.log("second read returned error: ", err);
    else
        if (data === null) 
            console.log("second read returned NULL data!");
        else if (data === "") 
            console.log("second read returned EMPTY data!");
        else
            console.log("second read returned data: ", data);
});


console.log("Done.");

The first thing the read in fs module does is request for meta data of the file, once it has that, it requests for permission to read the file, now, the three fs functions (read, write and read) are put into the thread pool, the first read requests for file meta data, gets it, before it requests to read, the write function starts writing(Note that write does not request for file meta data) and and other read requests for file meta data, gets it, since the disk is idle, the scheduler gives read access to the first read, once it's done, read access is given to the second read function.

Run this code and see your output explains why Node JS is also multithreaded.

NB: This can be forced to behave in a single threaded manner, but that's not our focus here.

PS: Node JS is only single threaded in it's event loop, anything outside it's event loop that requests for the OS is multithreaded. Things like http, file read/write, cryptography etc.

Thank you for reading this, if there's anything you would love for me to write about, please leave a comment in the comment section.

Hi, my name is Chuks, I'm a backend developer skilled in Node JS, C#, Docker and Kubernetes and I'm available for remote, contract and full time(relocation offers), send an email to chuksgpfr@gmail.com, follow me on twitter ChuksGPFR.