


How to understand that Node.js is not a completely single-threaded program (a brief analysis)
Why do we say Node.js is not completely single-threaded? How to understand? The following article will discuss it with you, I hope it will be helpful to you!
I believe everyone knows that node is a single-threaded program that uses Event Loop to achieve multiple concurrencies. Unfortunately this is not entirely correct.
So why is Node.js not a completely single-threaded program?
Node.js is a single-threaded program*
All the Javascript, V8, and event loops we wrote ourselves run in the same thread, which is the main thrad .
Hey, doesn’t this mean that node is single-threaded?
But maybe you don’t know that node has many modules with C code behind them.
Although node does not expose users to the permission to control threads, C can use multi-threading.
So when will node use multi-threading?
If a node method calls C's synchronous method behind the scenes, it will all run in the main thread.
If a node method calls C's asynchronous method behind the scenes, sometimes it does not run in the main thread.
Talk is cheap, show me the code.
Synchronous method, running in the main thread
Herecrypto
Many related modules are written in C. The following program is a function for calculating hash, which is generally used to store passwords.
import { pbkdf2Sync } from "crypto"; const startTime = Date.now(); let index = 0; for (index = 0; index < 3; index++) { pbkdf2Sync("secret", "salt", 100000, 64, "sha512"); const endTime = Date.now(); console.log(`${index} time, ${endTime - startTime}`); } const endTime = Date.now(); console.log(`in the end`);
Output time,
0 time, 44 1 time, 90 2 time, 134 in the end
You can see that it takes about 45ms each time, and the code is executed sequentially on the main thread.
Pay attention to who is the final output? Note that a hash here takes ~45ms on my CPU.
Asynchronous pbkdf2 method does not run in the main thread
import { cpus } from "os"; import { pbkdf2 } from "crypto"; console.log(cpus().length); let startTime = console.time("time-main-end"); for (let index = 0; index < 4; index++) { startTime = console.time(`time-${index}`); pbkdf2("secret", `salt${index}`, 100000, 64, "sha512", (err, derivedKey) => { if (err) throw err; console.timeEnd(`time-${index}`); }); } console.timeEnd("time-main-end");
The output time,
time-main-end: 0.31ms time-2: 45.646ms time-0: 46.055ms time-3: 46.846ms time-1: 47.159ms
As you can see here, the main thread is early At the end, however, the time for each calculation is 45ms. You must know that the time it takes for a CPU to calculate hash is 45ms. The node here definitely uses multiple threads for hash calculation.
If I change the number of calls here to 10, then the time is as follows. You can see that as the number of CPU cores is used up, the time is also increasing. Once again, it is proved that node definitely uses multiple threads for hash calculation.
time-main-end: 0.451ms time-1: 44.977ms time-2: 46.069ms time-3: 50.033ms time-0: 51.381ms time-5: 96.429ms // 注意这里,从第五次时间开始增加了 time-7: 101.61ms time-4: 113.535ms time-6: 121.429ms time-9: 151.035ms time-8: 152.585ms
Although it is proven here that node definitely has multi-threading enabled. But there is a little problem? The CPU of my computer is AMD R5-5600U, which has 6 cores and 12 threads. But why does the time increase from the fifth time? Node does not fully utilize my CPU?
what is the reason?
Node uses a predefined thread pool. The default size of this thread pool is 4.
export UV_THREADPOOL_SIZE=6
Let us take a look An example,
HTTP request
import { request } from "https"; const options = { hostname: "www.baidu.com", port: 443, path: "/img/PC_7ac6a6d319ba4ae29b38e5e4280e9122.png", method: "GET", }; let startTime = console.time(`main`); for (let index = 0; index < 15; index++) { startTime = console.time(`time-${index}`); const req = request(options, (res) => { console.log(`statusCode: ${res.statusCode}`); console.timeEnd(`time-${index}`); res.on("data", (d) => { // process.stdout.write(d); }); }); req.on("error", (error) => { console.error(error); }); req.end(); } console.timeEnd("main");
main: 13.927ms time-2: 83.247ms time-4: 89.641ms time-3: 91.497ms time-12: 91.661ms time-5: 94.677ms ..... time-8: 134.026ms time-1: 143.906ms time-13: 140.914ms time-10: 144.088ms
The main program here also ended early. Here I started http request to download pictures 15 times, but the time they spent did not succeed. Multiplying, it seems not to be affected by the thread pool/cpu.
Why? ? Is Node using a thread pool?
If the asynchronous method of C behind Node will first try to see if there is kernel asynchronous support, for example, please use epoll (Linux) for the network here. If the kernel does not provide an asynchronous method, Node will Will use its own thread pool. .
So although the http request is asynchronous, it is implemented by the kernel. After the kernel is completed, C will be notified, and C will notify the main thread to handle the callback.
So which asynchronous methods of Node use the thread pool? Which ones won’t?
-
Native Kernal Async
- TCP/UDP server client
- Unix Domain Sockets (IPC)
- pipes
- dns.resolveXXX
- tty input(stdin etc)
- Unix signals
- Child process
-
Thread pool
- fs.*
- dns.lookup
- pipe (edge case)
This It is also the entry point for most Node optimizations.
But how do these combine with the most important Event Loop?
Event Loop
I believe everyone is very familiar with Event loop. The event loop is like a distributor.
If it encounters an ordinary javascript program or callback, it is handed over to V8 for processing.
If you encounter a synchronization method written in C, hand it over to C and run it on the main thread.
If you encounter asynchronousThe back of the method is written in C. If there is kernel asynchronous support, it will be handed over from the main thread to the kernel for processing.
If it is asynchronousThe back of the method is written in C. If there is no kernel asynchronous support, it is handed over from the main thread to the thread pool.
Thread pool and the kernel will return the results to the event loop. If there is a javascript callback registered, it will be handed over to V8 for processing.
And then loop like this until there is nothing left to process.
So Node is not entirely a single-threaded program.
For more node-related knowledge, please visit: nodejs tutorial!
The above is the detailed content of How to understand that Node.js is not a completely single-threaded program (a brief analysis). For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



This article will give you an in-depth understanding of the memory and garbage collector (GC) of the NodeJS V8 engine. I hope it will be helpful to you!

The Node service built based on non-blocking and event-driven has the advantage of low memory consumption and is very suitable for handling massive network requests. Under the premise of massive requests, issues related to "memory control" need to be considered. 1. V8’s garbage collection mechanism and memory limitations Js is controlled by the garbage collection machine

Choosing a Docker image for Node may seem like a trivial matter, but the size and potential vulnerabilities of the image can have a significant impact on your CI/CD process and security. So how do we choose the best Node.js Docker image?

The file module is an encapsulation of underlying file operations, such as file reading/writing/opening/closing/delete adding, etc. The biggest feature of the file module is that all methods provide two versions of **synchronous** and **asynchronous**, with Methods with the sync suffix are all synchronization methods, and those without are all heterogeneous methods.

Node 19 has been officially released. This article will give you a detailed explanation of the 6 major features of Node.js 19. I hope it will be helpful to you!

How does Node.js do GC (garbage collection)? The following article will take you through it.

The event loop is a fundamental part of Node.js and enables asynchronous programming by ensuring that the main thread is not blocked. Understanding the event loop is crucial to building efficient applications. The following article will give you an in-depth understanding of the event loop in Node. I hope it will be helpful to you!

The reason why node cannot use the npm command is because the environment variables are not configured correctly. The solution is: 1. Open "System Properties"; 2. Find "Environment Variables" -> "System Variables", and then edit the environment variables; 3. Find the location of nodejs folder; 4. Click "OK".
