Is Node Really Single-Threaded?

Neelesh Dwivedi
Webtips
Published in
4 min readJun 27, 2020
Is Node Really Single-Threaded
Photo by Joshua Aragon on Unsplash

For all the professionals who are or were working on Node JS, they may have come across this question several times. We hear a lot of people say that node is single-threaded. Is this really the case? Well, let us find out.

In this article I am not going be typing any long paragraphs or else this article is going to be very boring. I will use a practical example and at the end of this article we are going to find out the answer to the question above i.e. IS NODE REALLY SINGLE THREADED?

Let’s really dive in with the code and I will try to explain what is going on along the way.

Here we have required the crypto module and defined a variable called start which we are using to identify the time at which the program execution was started. Then we call the pbkdf2 function of the crypto module(do not get into the nitty-gritty details of how pbkdf2 works. If you want to know how it works please feel free to look it up online). We have defined a console.log inside the pbkdf2 function also to just find out how much time the function call took. Just follow along with the example and you will soon get to know what I am trying to say.

If I try to run that on my system using node filename.js. I get the following as the output.

1: 611

If you get some different results, don’t panic. It depends on your system configuration. Next, we try to replicate that pbkdf2 function so now there are two pbkdf2 calls in our program. We just changed the 1 in the console.log of the second function to 2 as to identify the time taken for both the functions.

Now we again try to run that file.

2: 594
1: 595

So both the pbkdf2 functions complete at the same time. How can this be possible if node was single-threaded? If node was really single threaded we should be expecting the time of second pbkdf2 call to be something near twice the time of the first pbkdf2 call because it has to wait for the first call to finish then start executing which will take around twice the time it is already taking. Confused? Just try to have some patience I am going to explain what is happening really soon.

Next, we replicate the pbkdf2 function 2 more times so there are four pbkdf2 function calls now. Let us do that and see what happens.

Let us now again run the file and analyse the output.

4: 590
3: 602
2: 615
1: 615

It seems that all the four function calls are taking almost the same time to execute. So much for a single-threaded application right? Just follow on for a little bit more.

Now we add another pbkdf2 function call so that there are a total of five function call now.

Now we try to run the following file and see what the output is.

2: 586
1: 597
4: 614
3: 629
5: 1173

This time the fifth function took almost double time. It seems that multiple threads are at work so how is node single-threaded and why the heck does fifth function call took so much time?

Whenever we fire up a node application it starts up a single thread and in that single thread node sets up an event loop. So there is only one single thread and one event loop per node program. But the pbkdf2 function call is not managed by the node event loop. It is managed by libuv outside of the event loop. Libuv utilises something called thread pool which contains a collection of 4 threads by default. So that is why for the first four cases the execution time was almost similar but for the fifth case it had to wait for at least one function call to finish and after that only it could be assigned a thread for execution. So that is why the last pbkdf2 function took almost twice the execution time.

Bonus

There is a variable in the Node process env object called UV_THREADPOOL_SIZE which can be used to alter the default size of the thread pool. Just put this line at the start of the code and just watch the output.

Let us see the output in this case.

2: 586
1: 610
3: 1173
4: 1200
5: 1760

It seems quite obvious now that since we have reduced the number of threads in the thread pool to 2 so the function will be executed in the batches of two. So only two threads are available for the execution of the programs.

Now try increasing the size of the thread pool. This is left as an exercise for the reader. Just play with the code and have fun.

PS: You can find the total number of cores in your system using lscpu command. Try running it in the terminal.

Conclusion

At the beginning of this article, we did not know if node was actually single-threaded or not. But now we have some idea that node is not entirely single-threaded but only some part of node is single-threaded.

If you like this article please give me a clap.

--

--

Neelesh Dwivedi
Webtips
Writer for

A burning sense of passion is the most potent fuel for your dreams.