Javascript/Multithreading in NodeJS \342\200\224 using worker threads.md
... ...
@@ -0,0 +1,298 @@
1
+https://medium.com/engineering-at-bajaj-health/multithreading-in-nodejs-using-worker-threads-61463c39861c
2
+
3
+# Multithreading in NodeJS — using worker threads | by Subhanu | Engineering at Bajaj Health | Medium
4
+
5
+![Subhanu](https://miro.medium.com/v2/resize:fill:88:88/1*Ik7AS94x5dUi5YXq7Udx4A.jpeg)
6
+[Subhanu](https://medium.com/@subhanusroy)
7
+
8
+
9
+![Engineering at Bajaj Health](https://miro.medium.com/v2/resize:fill:48:48/1*yb3VOeuvapHzGOM1cMWMhA.png)
10
+[Engineering at Bajaj Health](https://medium.com/engineering-at-bajaj-health)
11
+
12
+Whether you are
13
+
14
+* a _seasoned pro_ using NodeJS to build a scalable backend which involves some complex tasks like processing images, uploading PDFs, encryption, etc, or
15
+* someone who is shifting from a multithreaded language like Java or Go to NodeJS, or
16
+* a complete _beginner_ learning backend in Javascript
17
+
18
+this article will help you understand what **NodeJS** is, its **limitations**, what **multithreading** is, and how to get started with **Multithreading in NodeJS**.
19
+
20
+So let’s dive right in!
21
+
22
+What is NodeJS?
23
+---------------
24
+
25
+NodeJS is a **server-side Javascript run time** built on the V8 JS engine which has gained immense popularity in the development community because of its
26
+
27
+* event-driven,
28
+* non-blocking input-output model
29
+
30
+which makes it well-suited for building i/o based **scalable** and **high-performance** applications
31
+
32
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*uaXPLbNrJTycs28U.png)
33
+Inner working of NodeJs — GeeksForGeeks
34
+
35
+What are its limitations?
36
+-------------------------
37
+
38
+NodeJs is **single threaded** which makes handling multiple IO-bound requests easy.
39
+
40
+But when there are **CPU-intensive tasks** like converting an html to a pdf, compression of documents, image processing or doing a complex calculation, NodeJs is not at all efficient.
41
+
42
+Some cons of the single-threaded nature of NodeJs are:
43
+
44
+**Blocking Operations**
45
+-----------------------
46
+
47
+Any blocking operation can potentially stall the entire application in a single-threaded environment. CPU-bound tasks or operations with significant processing time can lead to delays in handling other events.
48
+
49
+**Example 1 — Hashing elements in a large array**
50
+
51
+We have to perform CPU-intensive tasks like hashing every element in a vast array using the crypto module
52
+
53
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/1*w-lKTqvAKrKXJLw-7g5jyQ.png)
54
+Hashing all elements of a large array
55
+
56
+This block of code takes a lot of computational time.
57
+
58
+Since Node.js runs callbacks registered for events in the Event Loop, this callback code will block the Event Loop thread and cannot handle requests from other clients until it finishes its execution.
59
+
60
+**Example 2 — Calculating the nth Fibonacci number (n>35)**
61
+
62
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/1*VSuYVlQ0ZjO9BZNB8DwJpg.png)
63
+nth Fibonacci Number
64
+
65
+In this example, we have a simple recursive function to calculate the Fibonacci sequence. The recursive nature of the function makes it computationally expensive. When running this function with a large value of n in a single-threaded Node.js environment, it can lead to a significant delay in processing other tasks. The event loop gets blocked, and the application becomes less responsive.
66
+
67
+**Example 3 — Image Processing**
68
+
69
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/1*G4EESqeck3INDiIsnrtcyw.png)
70
+Resizing and grayscaling an image using sharp
71
+
72
+In this example, we use the sharp library to perform image processing tasks such as resizing and converting to grayscale. Image processing, especially with large files, can be CPU-intensive. When executing this code in a single-threaded environment, it may take a considerable amount of time to process the image, impacting the responsiveness of the application for other tasks.
73
+
74
+**Limited CPU Utilization**
75
+---------------------------
76
+
77
+Node.js cannot fully utilize multi-core processors due to its single-threaded architecture. In scenarios where parallel processing could significantly improve performance, the single-threaded model falls short.
78
+
79
+Cons of single-threaded NodeJs: Limited CPU Utilization
80
+
81
+**Scalability Challenges**
82
+--------------------------
83
+
84
+Scaling vertically (adding more resources to a single server) can only go so far. Horizontal scaling (adding more servers) is often preferred, but Node.js, in its native form, may not fully leverage the potential of multi-core servers.
85
+
86
+Vertical scaling on the left, horizontal scaling on the right
87
+
88
+Multithreading vs Single-Threaded Languages
89
+-------------------------------------------
90
+
91
+In the simplest of terms,
92
+
93
+> Single-threaded languages can only execute one task at a time, while multi-threaded languages can execute multiple tasks simultaneously.
94
+
95
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*q8BP6_4Fbpp-Btbc.png)
96
+Single-threaded vs Multithreaded
97
+
98
+Single-threaded languages are straightforward and suitable for simple applications. They are also easy to debug and maintain because of their sequential nature.
99
+
100
+Multi-threaded languages can potentially improve performance and responsiveness. For example, Apache servers use a multi-threading mechanism to handle multiple requests simultaneously.
101
+
102
+Ok so now we have understood theoretically, let's look at it practically.
103
+
104
+Performance testing single-threaded NodeJS
105
+------------------------------------------
106
+
107
+We will create a simple node-express server with 2 routes:
108
+
109
+* “/” route: will be a simple non-blocking operation
110
+* “/blocking” route: will perform the calculation of the 45th Fibonacci number
111
+
112
+Then we will check the response times for 3 scenarios:
113
+
114
+1. Send a request to “/”
115
+2. Send a request to “blocking”
116
+3. Send request to “/” while “/blocking” is in progress
117
+
118
+Setup Project
119
+-------------
120
+
121
+Go to any directory of your choice and run the below command in the terminal:
122
+
123
+```
124
+npm init
125
+```
126
+
127
+
128
+Index.js file
129
+-------------
130
+
131
+```
132
+import express from "express";
133
+const app = express()
134
+const port = process.env.PORT || 5000;
135
+// Making 2 routes: normal and blocking
136
+app.get("/", (req, res) => {
137
+ res.status(200).send("normal non-blocking page");
138
+});
139
+app.get("/blocking", async (req, res) => {
140
+ function fibonacci(n) {
141
+ if (n <= 1) return n;
142
+ return fibonacci(n - 1) + fibonacci(n - 2);
143
+ }
144
+ const result = fibonacci(45);
145
+ res.status(200).send(`fibonacci(45) is : ${result}`);
146
+});
147
+app.listen(port, () => {
148
+ console.log("Learning multithreading on port ", port);
149
+});
150
+```
151
+
152
+
153
+So now let's start the server with
154
+
155
+```
156
+node index.js
157
+```
158
+
159
+
160
+And observe the response times in different scenarios:
161
+
162
+**Hitting “/” the first time:**
163
+-------------------------------
164
+
165
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*YxULddxSzJyUxbR9)
166
+
167
+response takes **12ms**
168
+
169
+**Hitting “/blocking” first time:**
170
+-----------------------------------
171
+
172
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*t3H2bTB3IAgJgZQh)
173
+Takes **14+ seconds**
174
+
175
+**Hitting “/” while “/blocking” is running:**
176
+---------------------------------------------
177
+
178
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*6on_a2JyXd_8obb2)
179
+
180
+Takes **13.36 seconds** (more than a **100,000% increase** in response time)
181
+
182
+Why this behavior?
183
+------------------
184
+
185
+When “/blocking” runs, it performs the Fibonacci calculation of 45. The **recursive nature** of the function makes it **computationally expensive**.
186
+
187
+So when this runs, the event loop is blocked by this route, and even if you hit “/” at that time, Node can't serve the simple response of “/”, since it is single-threaded.
188
+
189
+So how to fix this issue?
190
+
191
+Enter Multithreading in NodeJs using the worker\_thread module.
192
+
193
+**Worker Threads module**
194
+-------------------------
195
+
196
+So in NodeJs [V12.11](https://nodejs.org/en/blog/release/v12.11.0/), the **worker\_threads** module was made stable, and they introduced it as
197
+
198
+> _Workers (threads) are useful for performing CPU-intensive JavaScript operations._
199
+
200
+This module enables the use of threads that execute JS in parallel.
201
+
202
+Code executed in a worker thread runs in a **separate child process** preventing it from blocking your main operation.
203
+
204
+Let's solve the above issue using the worker threads module.
205
+
206
+**Make a worker.js file**
207
+-------------------------
208
+
209
+Here we will **move the CPU-intensive function** and execute the function.
210
+
211
+Then pass the result using the postMessage function, which communicates with the main thread.
212
+
213
+```
214
+import { parentPort } from "worker_threads";
215
+//move the function here
216
+function fibonacci(n) {
217
+ if (n <= 1) return n;
218
+ return fibonacci(n - 1) + fibonacci(n - 2);
219
+}
220
+const result = fibonacci(45);
221
+// pass the result to parent thread
222
+parentPort.postMessage(result)
223
+```
224
+
225
+
226
+**Add the worker in the index2.js file**
227
+----------------------------------------
228
+
229
+So now we make a copy of the index file in the index2 file, except we will make the new changes in the index2 file as follows:
230
+
231
+```
232
+import express from "express";
233
+// import worker
234
+import { Worker } from "worker_threads";
235
+const app = express();
236
+const port = process.env.PORT || 5000;
237
+app.get("/", (req, res) => {
238
+ res.status(200).send("normal non-blocking page");
239
+});
240
+app.get("/blocking", async (req, res) => {
241
+ // constructor a worker, where you pass the path of your worker file
242
+ const worker = new Worker("./worker.js");
243
+ // handle when worker thread sends a message to parent
244
+ worker.on("message", (data) => {
245
+ res.status(200).send(`fibonacci(45) is : ${data}`);
246
+ });
247
+ // handle when worker thread sends an error to parent
248
+ worker.on("error", (error) => {
249
+ res.status(404).send(`failed to perform: ${error}`);
250
+ });
251
+});
252
+app.listen(port, () => {
253
+console.log("Learning multithreading on port ", port);
254
+});
255
+```
256
+
257
+
258
+Testing the API as per the 3 scenarios
259
+--------------------------------------
260
+
261
+So let's test the API based on the three scenarios above and observe how the response time has changed for 3rd scenario which is _Send request to “/” while “/blocking” is in progress_
262
+
263
+Hitting “/” :
264
+-------------
265
+
266
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*if-siQRATkfTvWg1)
267
+Takes 3ms
268
+
269
+**Hitting “/blocking”:**
270
+------------------------
271
+
272
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*oJKvkChSNRKSOdeF)
273
+Takes 14 seconds as usual
274
+
275
+**Hitting “/” while “/blocking” is in progress:**
276
+
277
+![](https://miro.medium.com/v2/resize:fit:720/format:webp/0*k1phaAxm_GwbbZKz)
278
+takes 3ms (same as if it hit normally)
279
+
280
+**Why this improvement?**
281
+-------------------------
282
+
283
+The “/blocking” is now running on the worker thread (child) while the “/” is working on the main thread. Both are independent of each other.
284
+
285
+We avoid blocking the Event Loop, so it can serve other clients’ requests, improving our application performance.
286
+
287
+Conclusion
288
+----------
289
+
290
+Multithreading in NodeJS empowers Node to a great extent and nullifies the cons of it being a single-threaded run time. In this article, we also saw how we can solve an issue caused by single threading using the worker\_threads module (with proof of API performance)
291
+
292
+Worker Threads has a lot of other features for communication with the main thread, creating multiple child threads, etc. which can be read in the official [worker threads documentation](https://nodejs.org/api/worker_threads.html).
293
+
294
+**Note**: Despite the multi-threaded superpowers added to single-threaded NodeJS, if you are building a scalable backend which has mostly CPU intensive tasks, it’s better to work with a language which supports multi-threading in itself like Java, Go Lang etc.
295
+
296
+Thank you for reading, and happy coding!
297
+
298
+Cheers 🥂
... ...
\ No newline at end of file