Open In App

How single threaded handles concurrency when multiple I/O operations happening in Node.js ?

Last Updated : 07 Sep, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

Node JS is one of the most popular runtime environments, to build backend servers. Despite of its single-threaded nature, Node JS performs quite well because of its asynchronous and non-blocking behavior. It is regularly used to build backend servers that interact with websites, mobile applications, and more. Let’s take a look at the topic-

How single threaded Node JS handles concurrency when multiple I/O operations are happening?

It means that, how does Node JS handle multiple client requests, even when it uses a single thread? Using a single thread would mean, that it would handle the request and response of a single client at a time. So, how does Node JS work when multiple clients are firing requests?

Node JS uses the concept of asynchronous and non-blocking behavior. But first, let’s understand the terms: single-threaded and concurrency.

  • Single Threaded: Node JS works using a single thread. This means that there isn’t a pool of threads, which is assigned to handle client requests, but only a single thread to accept the incoming requests. So, even if there are 100 clients, we have a single thread to handle them, in one server.
  • Concurrency: When requests are fired by more than one client at the same time, it is referred to as concurrency. For example, the official website of google is daily visited by hundreds of people at the same time. This is concurrency.

Let’s look at the approaches to handling client requests:

1. Synchronous and Blocking behavior: This means, that the thread will accept a single client request, send it to some other server or database, and wait for the response (blocking behavior). As soon as it receives the response, it returns the response to the client, and now accepts the request from the second client (synchronous). This means, that subsequent clients have to wait for their response until the previous clients have received their response, which is not practical in our case.

2. Asynchronous and Non-blocking behavior: This is what is used by Node JS. This means that the thread will accept the first client’s request, send the request to a pool of working threads, and become free to accept the second client’s request (non-blocking behavior). This way it can handle multiple or concurrent client requests at the same time. As soon as the response is ready, the pool of threads sends it back to the main thread via callbacks (asynchronous behavior). As soon as the thread receives the response, it returns the response to the respective client. This is how Node JS handles concurrency.

Let’s understand this through the following code examples:

NOTE: Create a file called server.js, that we will be using for both examples:

Example 1: In this example, we’ll be seeing how to Handle a single client request:

Javascript




const express = require('express');
const app = express();
const port = 5000;
  
app.get('/', (req, res) => {
    res.send('Hello World!');
    console.log('Hello World!');
})
  
app.listen(port, () => {
    console.log(`Server is running at the port: ${port}`);
})


Steps to run the server: Run the code with the following command: 

node server.js

Output: Now go to your browser and type in the http://localhost:5000/. You will see a webpage saying Hello World.

Server is running at the port: 5000
Hello World!

Explanation: So, what the code is doing is, it is receiving a client request at the URL http://localhost:5000/ using the app.get and sending the output to the client using res.send. Also, we are printing the output in the console, using console.log.

Example 2: In this example, we’ll be seeing how to Handle multiple or concurrent client requests:

Javascript




const express = require('express');
const app = express();
const port = 5000;
  
const multipleClients = async () => {
    await console.log('Hello World!');
}
  
app.get('/', (req, res) => {
    multipleClients();
})
  
app.listen(port, () => {
    console.log(`Server is running at the port: ${port}`);
})


Steps to run the server: Run the code with the following command: 

node server.js

Output: Now, go to your browser, and type in the http://localhost:5000/ at multiple tabs. In this case, I have used three tabs. Now come back to your console. You should get the following output:

Server is running at the port: 5000
Hello World!
Hello World!
Hello World!

Explanation: As you can see, some part is similar to the previous example. In this case, we are creating a new function called multipleClients. This is an asynchronous function. We have used the async keyword. So, when we fire multiple client requests at the URL http://localhost:5000/, app.get calls the function multipleClients. Since this is an asynchronous function, the main thread sends this request to the pool of working threads and waits for the response. Observe, that we have used the await for the same purpose. And the thread becomes free to accept the request from another user. As and when the response is returned to the main thread by the pool of threads, the main thread returns the response to the client, and we can see the output in our console as ‘Hello World!‘. This demonstrates the Asynchronous and Non-Blocking behavior of Node JS.

This is how we can handle concurrency in Node JS, using the async and await keywords.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads