Is NodeJs Single Threaded – Let’s Find Out
|NodeJS is single threaded, hmm yes but this is a partial truth, actually it is event-driven and single-threaded with background workers. NodeJS is based on JavaScript and C++. JavaScript executes on the server by google chrome v8 engine and libuv library, written in C++, take care of non-blocking I/O through background workers.
How Threads Work In NodeJS
What makes NodeJS unique is the way in which it manages event-driven asynchronous operations for us and this where the concept of an Event Loop comes into the picture.
var sockets = require('websocket.io'),httpServer = sockets.listen(4000); httpServer.on('onConnection', function (socket) { console.log('connected……'); httpServer.send('Web socket connected.'); httpServer.on('message', function (data) { console.log('message received:', data); }); httpServer.on('close', function () { console.log('socket closed!'); }); });
In above code snippet, as soon as ws.listen(4000) executes, a Web-Socket server is created on a single thread – event loop which listens continuously on port 4000. When a client connects to it, it fires the ‘onConnection’ event which the loop picks up and immediately publishes to the thread pool and is ready to receive the next request.
And this is where NodeJS based server different from IIS/ Apache and the basic difference is that NodeJS do not create new threads for every incoming request but receive all requests of single thread and pass these work items to background workers if required. These workers managed through libuv library and Operating System.
In simple words if my NodeJS server receives 100 requests simultaneously, they all will be received by single event loop thread and then they can be passed to background workers, which actually execute it. When the worker finishes its execution, registered success callback will be invoked again on event loop thread to pass the result back to the user.
Let‘s try with another in-depth example: We basically need to understand how NodeJS executes the code. NodeJS execution model is different from runtime environments like Python, Ruby, C# or Java.
Let’s take a very simple piece of code like this:
var queryResult = db.query("select * from mytable"); console.log("Executed………….");
The first line queries a database for lots of rows, the second line puts “Executed ………” to the console. Let’s assume that the database query is quite slow, that it has to read a lot of rows, which takes noticeable time. The way we have written this code, the JavaScript interpreter of NodeJS first has to read the complete result set from the database, and then it can execute the console.log() function. During the time of this query execution, our server will not able to process any further request as this all operation is going on NodsJS event loop thread ( 1 in above figure).
If this piece of code actually was C#, it would work the same way and would take approx. same amount of time but it would not block any other user or in other words it would not block the request receiver server as IIS assigned a new thread to every request and this request execute independently.
But the execution model of Node.js is different and there is only one single process to receive the requests and if this process blocked, it would not able to receive new requests until it get unblocked from its ongoing task. If there is a slow database query somewhere in this process, this affects the whole process – everything comes to a halt until the slow query has finished.
To avoid this, we can rewrite our code:
db.query("select * from mytable", function(rows) { var result = rows; }); console.log("Hello World");
Here, instead of expecting database.query() to directly return the result to us, we pass it as a second parameter, an anonymous function. In its previous form, our code was synchronous: first do the database query and wait for its completion, and only when this is done, then write to the console. Now, NodeJS can handle the database request asynchronously and delegate this task to workers as shown in (2 in above figure). Provided that database.query() is part of an asynchronous library and now instead of waiting for it to be finished, it makes a contract which says “When database query will be executed, I have to execute the anonymous function that was passed to database.query().” Then, it immediately executes console.log(), and enters into the event loop. NodeJS continuously cycles through this loop waiting for events. Completion of the database query is also an event published to the event loop.
How to increase the number of background threads
The libuv library manage threads pool that is used by NodeJS to perform long-running operations in the background, without blocking its main thread as we discussed above. We can visit here to more details of LIBUV.
The thread pool is used through submitting a work request to a queue and it contains:
- A function to execute in the worker thread.
- A structure for result data.
- A function to collect the processed results.
This thread pool works as any other standard pooling works. It has some limited amount of threads and these threads allocated to in coming requests. If all threads are busy, the new request will have to wait for its turn.
process.env.UV_THREADPOOL_SIZE =12;
By default size of libuv’s thread pool is 4. We can set number of background threads with UV_THREADPOOL_SIZE environment variable. We cannot change thread pool size once it is created and it is created on the first request.
Although I am a novice in NodeJS world but still I hope the post provide you some insight for NodeJS and its execution model. I would sincerely appreciate your inputs as comments and feedback to enhance the quality of the post.
Hello Rahul,
This is really helpful for experienced or novice both. Great Article, keep posting more. Ton of Thanks.
I glad it helped you.
I am have been looking for and read many other explainations on this subject recently as part of a college project and yours is by far the best.
Thanks Shea !!!
I really like the post. However, I think that select statement will not work – “select * f[ro]m mytable”
Thanks for pointing out.
Hello Rahul.. This is too good but I want to one thing that how this server handles several request with single thread internally?
Sorry for long delay to reply. By default nodeJs initialize one thread (event loop thread) per cpu. This single thread just work to receive and to reply, while any manipulation, network call and other resource intensive work delegated to background workers. As soon as background workers finish their work, they post responce to the event loop thread and thus response will be returned to user.
Thanks. I figured out now how the event-loop is not blocking-thread.