A brief discussion on multi-threaded operations in Nodejs
Although nodejs is single-threaded, it still allows multi-threaded operations. This article will start with Node threads, talk about multi-threaded operations in Nodejs, and introduce the worker_threads template.
The test environment for this article:
System: macOS Mojave 10.14.2
CPU: 4 cores 2.3 GHz
Node: 10.15.1
[Recommended learning: "nodejs Tutorial"]
Start with Node threads
Most people understand Node It is single-threaded, so the number of threads should be 1 after Node is started. Let's do an experiment and see. [Recommended study: "nodejs Tutorial"]
setInterval(() => { console.log(new Date().getTime()) }, 3000)
You can see that the Node process occupies 7 threads. Why are there 7 threads?
We all know that the core of Node is the v8 engine. After Node is started, an instance of v8 will be created. This instance is multi-threaded.
- Main thread: compile and execute code.
- Compile/optimize thread: When the main thread executes, the code can be optimized.
- Analyzer thread: records the analysis code running time to provide a basis for Crankshaft to optimize code execution.
- Several threads for garbage collection.
So everyone often says that Node is single-threaded, which means that the execution of JavaScript is single-threaded, but the host environment of Javascript, whether it is Node or the browser, is multi-threaded.
Node has two compilers:
full-codegen: simply and quickly compile js into simple but slow machine code.
Crankshaft: A relatively complex real-time optimization compiler that compiles high-performance executable code.
Some asynchronous IO will occupy additional threads
Still the above example, we read a file while the timer is executing:
const fs = require('fs') setInterval(() => { console.log(new Date().getTime()) }, 3000) fs.readFile('./index.html', () => {})
The number of threads becomes 11. This is because there are some IO operations (DNS, FS) and some CPU-intensive calculations (Zlib, Crypto) in Node that enable Node The thread pool, and the default size of the thread pool is 4, because the number of threads becomes 11.
We can manually change the default size of the thread pool:
process.env.UV_THREADPOOL_SIZE = 64
Easily change the threads to 71 with one line of code.
#cluster Is it multi-threaded?
The single thread of Node also brings some problems, such as insufficient utilization of the CPU, an uncaught exception may cause the entire program to exit, etc. Because the cluster module is provided in Node, cluster implements the encapsulation of child_process and implements the multi-process model by creating child processes through the fork method. For example, pm2, which we use most often, is the best representative among them.
Let’s look at a cluster demo:
const cluster = require('cluster'); const http = require('http'); const numCPUs = require('os').cpus().length; if (cluster.isMaster) { console.log(`主进程 ${process.pid} 正在运行`); for (let i = 0; i < numCPUs; i++) { cluster.fork(); } cluster.on('exit', (worker, code, signal) => { console.log(`工作进程 ${worker.process.pid} 已退出`); }); } else { // 工作进程可以共享任何 TCP 连接。 // 在本例子中,共享的是 HTTP 服务器。 http.createServer((req, res) => { res.writeHead(200); res.end('Hello World'); }).listen(8000); console.log(`工作进程 ${process.pid} 已启动`); }
At this time, look at the activity monitor:
There are 9 processes in total, among which A main process, the number of CPUs x the number of CPU cores = 2 x 4 = 8 child processes.
So neither child_process nor cluster is a multi-thread model, but a multi-process model. Although developers are aware of the problems of the single-threaded model, they do not fundamentally solve the problem and provide a multi-process method to simulate multi-threading. From the previous experiments, we can see that although Node (V8) itself has multi-threading capabilities, developers cannot make good use of this capability. Instead, they use multi-threading in some ways provided by the bottom layer of Node. Node official said:
You can use the built-in Node Worker Pool by developing a C addon. On older versions of Node, build your C addon using NAN, and on newer versions use N-API . node-webworker-threads offers a JavaScript-only way to access Node's Worker Pool.
But for JavaScript developers, there has never been a standard and easy-to-use way to use Node's multi-threading capabilities. .
True - Node multi-threading
Until the release of Node 10.5.0, the official gave an experimental module worker_threads to Node Provides true multi-threading capabilities.
Let’s take a look at the simple demo first:
const { isMainThread, parentPort, workerData, threadId, MessageChannel, MessagePort, Worker } = require('worker_threads'); function mainThread() { for (let i = 0; i < 5; i++) { const worker = new Worker(__filename, { workerData: i }); worker.on('exit', code => { console.log(`main: worker stopped with exit code ${code}`); }); worker.on('message', msg => { console.log(`main: receive ${msg}`); worker.postMessage(msg + 1); }); } } function workerThread() { console.log(`worker: workerDate ${workerData}`); parentPort.on('message', msg => { console.log(`worker: receive ${msg}`); }), parentPort.postMessage(workerData); } if (isMainThread) { mainThread(); } else { workerThread(); }
The above code opens five sub-threads in the main thread, and the main thread sends simple messages to the sub-threads.
由于 worker_thread 目前仍然处于实验阶段,所以启动时需要增加 --experimental-worker
flag,运行后观察活动监视器:
不多不少,正好多了五个子线程。
worker_thread 模块
worker_thread 核心代码
worker_thread 模块中有 4 个对象和 2 个类。
- isMainThread: 是否是主线程,源码中是通过
threadId === 0
进行判断的。 - MessagePort: 用于线程之间的通信,继承自 EventEmitter。
- MessageChannel: 用于创建异步、双向通信的通道实例。
- threadId: 线程 ID。
- Worker: 用于在主线程中创建子线程。第一个参数为 filename,表示子线程执行的入口。
- parentPort: 在 worker 线程里是表示父进程的 MessagePort 类型的对象,在主线程里为 null
- workerData: 用于在主进程中向子进程传递数据(data 副本)
来看一个进程通信的例子:
const assert = require('assert'); const { Worker, MessageChannel, MessagePort, isMainThread, parentPort } = require('worker_threads'); if (isMainThread) { const worker = new Worker(__filename); const subChannel = new MessageChannel(); worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]); subChannel.port2.on('message', (value) => { console.log('received:', value); }); } else { parentPort.once('message', (value) => { assert(value.hereIsYourPort instanceof MessagePort); value.hereIsYourPort.postMessage('the worker is sending this'); value.hereIsYourPort.close(); }); }
更多详细用法可以查看官方文档。
多进程 vs 多线程
根据大学课本上的说法:“进程是资源分配的最小单位,线程是CPU调度的最小单位”,这句话应付考试就够了,但是在实际工作中,我们还是要根据需求合理选择。
下面对比一下多线程与多进程:
属性 | 多进程 | 多线程 | 比较 |
---|---|---|---|
数据 | 数据共享复杂,需要用IPC;数据是分开的,同步简单 | 因为共享进程数据,数据共享简单,同步复杂 | 各有千秋 |
CPU、内存 | 占用内存多,切换复杂,CPU利用率低 | 占用内存少,切换简单,CPU利用率高 | 多线程更好 |
销毁、切换 | 创建销毁、切换复杂,速度慢 | 创建销毁、切换简单,速度很快 | 多线程更好 |
coding | 编码简单、调试方便 | 编码、调试复杂 | 多进程更好 |
可靠性 | 进程独立运行,不会相互影响 | 线程同呼吸共命运 | 多进程更好 |
分布式 | 可用于多机多核分布式,易于扩展 | 只能用于多核分布式 | 多进程更好 |
上述比较仅表示一般情况,并不绝对。
work_thread 让 Node 有了真正的多线程能力,算是不小的进步。
更多编程相关知识,请访问:编程视频!!
The above is the detailed content of A brief discussion on multi-threaded operations in Nodejs. 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

AI Hentai Generator
Generate AI Hentai for free.

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

The main differences between Node.js and Java are design and features: Event-driven vs. thread-driven: Node.js is event-driven and Java is thread-driven. Single-threaded vs. multi-threaded: Node.js uses a single-threaded event loop, and Java uses a multi-threaded architecture. Runtime environment: Node.js runs on the V8 JavaScript engine, while Java runs on the JVM. Syntax: Node.js uses JavaScript syntax, while Java uses Java syntax. Purpose: Node.js is suitable for I/O-intensive tasks, while Java is suitable for large enterprise applications.

Function exception handling in C++ is particularly important for multi-threaded environments to ensure thread safety and data integrity. The try-catch statement allows you to catch and handle specific types of exceptions when they occur to prevent program crashes or data corruption.

To connect to a MySQL database, you need to follow these steps: Install the mysql2 driver. Use mysql2.createConnection() to create a connection object that contains the host address, port, username, password, and database name. Use connection.query() to perform queries. Finally use connection.end() to end the connection.

Concurrency and multithreading techniques using Java functions can improve application performance, including the following steps: Understand concurrency and multithreading concepts. Leverage Java's concurrency and multi-threading libraries such as ExecutorService and Callable. Practice cases such as multi-threaded matrix multiplication to greatly shorten execution time. Enjoy the advantages of increased application response speed and optimized processing efficiency brought by concurrency and multi-threading.

PHP multithreading refers to running multiple tasks simultaneously in one process, which is achieved by creating independently running threads. You can use the Pthreads extension in PHP to simulate multi-threading behavior. After installation, you can use the Thread class to create and start threads. For example, when processing a large amount of data, the data can be divided into multiple blocks and a corresponding number of threads can be created for simultaneous processing to improve efficiency.

Mutexes are used in C++ to handle multi-threaded shared resources: create mutexes through std::mutex. Use mtx.lock() to obtain a mutex and provide exclusive access to shared resources. Use mtx.unlock() to release the mutex.

In a multi-threaded environment, C++ memory management faces the following challenges: data races, deadlocks, and memory leaks. Countermeasures include: 1. Use synchronization mechanisms, such as mutexes and atomic variables; 2. Use lock-free data structures; 3. Use smart pointers; 4. (Optional) implement garbage collection.

Node.js is a JavaScript runtime environment and npm is its package manager. The two work together to enable developers to write server-side programs in JavaScript, use third-party modules, and easily manage modules.
