Heim > Artikel > Web-Frontend > Eine kurze Diskussion über Multithread-Operationen in Nodejs
Obwohl nodejs Single-Threaded ist, ermöglicht es dennoch Multithread-Operationen. Dieser Artikel beginnt mit Node-Threads, spricht über Multithread-Operationen in Nodejs und stellt die worker_threads-Vorlage vor.
Die Testumgebung für diesen Artikel:
System: macOS Mojave 10.14.2
CPU: 4 Kerne 2,3 GHz
Knoten: 10.15.1
[Empfohlenes Lernen: „nodejs-Tutorial“]
Die meisten Leute verstehen, dass Node Single-Threaded ist, daher sollte die Anzahl der Threads nach dem Start von Node 1 sein. Lassen Sie uns ein Experiment durchführen, um das zu sehen. [Empfohlenes Lernen: „nodejs-Tutorial“]
setInterval(() => { console.log(new Date().getTime()) }, 3000)
Sie können sehen, dass der Node-Prozess 7 Threads belegt. Warum gibt es 7 Threads?
Wir alle wissen, dass der Kern von Node die v8-Engine ist. Nach dem Start von Node wird eine Instanz von v8 erstellt.
Wenn also oft gesagt wird, dass Node ein Single-Thread ist, bedeutet dies, dass die Ausführung von JavaScript Single-Thread ist, die Host-Umgebung von Javascript jedoch, egal ob Node oder Browser, Multi-Thread ist.
Node verfügt über zwei Compiler:
Full-Codegen: Kompilieren Sie js einfach und schnell in einfachen, aber langsamen mechanischen Code.
Crankshaft: Ein relativ komplexer Echtzeit-Optimierungscompiler, der leistungsstarken ausführbaren Code kompiliert.
Im obigen Beispiel lesen wir eine Datei, während der Timer ausgeführt wird:
const fs = require('fs') setInterval(() => { console.log(new Date().getTime()) }, 3000) fs.readFile('./index.html', () => {})
Die Anzahl der Threads beträgt 11, das liegt daran, dass es einige E/A gibt Vorgänge (DNS, FS) und einige CPU-intensive Berechnungen (Zlib, Crypto) in Node, Nodes Thread-Pool wird aktiviert und die Standardgröße des Thread-Pools beträgt 4, da die Anzahl der Threads 11 beträgt.
Wir können die Standardgröße des Thread-Pools manuell ändern:
process.env.UV_THREADPOOL_SIZE = 64
Ändern Sie die Threads mit einer Codezeile ganz einfach auf 71.
Der einzelne Thread von Node bringt auch einige Probleme mit sich, z. B. eine unzureichende Auslastung der CPU, eine nicht abgefangene Ausnahme kann dazu führen, dass das gesamte Programm beendet wird usw. Da das Clustermodul in Node bereitgestellt wird, implementiert der Cluster die Kapselung von child_process und implementiert das Multiprozessmodell, indem untergeordnete Prozesse über die Fork-Methode erstellt werden. Beispielsweise ist pm2, das wir am häufigsten verwenden, der beste Vertreter unter ihnen.
Sehen wir uns eine Cluster-Demo an:
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} 已启动`); }
Sehen Sie sich zu diesem Zeitpunkt den Aktivitätsmonitor an:
Es gibt insgesamt 9 Prozesse, einer davon ist der Hauptprozess, die Anzahl der CPUs x die Anzahl der CPUs Kerne = 2 x 4 = 8 Teilprozesse verarbeiten.
Also ist weder child_process noch Cluster ein Multi-Thread-Modell, sondern ein Multi-Prozess-Modell. Obwohl Entwickler sich der Probleme des Single-Threaded-Modells bewusst sind, lösen sie das Problem nicht grundlegend und stellen eine Multiprozessmethode zur Simulation von Multithreading bereit. Aus den vorherigen Experimenten können wir erkennen, dass Node (V8) zwar selbst über Multithreading-Fähigkeiten verfügt, Entwickler diese Fähigkeit jedoch nicht sinnvoll nutzen können. Stattdessen nutzen sie Multithreading in gewisser Weise, das von der untersten Ebene von Node bereitgestellt wird. Node-Beamter sagte:
Sie können den integrierten Node-Worker-Pool verwenden, indem Sie ein C++-Add-on entwickeln. Erstellen Sie Ihr C++-Add-on mit NAN und verwenden Sie bei neueren Versionen N-API bietet eine reine JavaScript-Methode für den Zugriff auf den Worker-Pool von Node.
Aber für JavaScript-Entwickler gab es nie eine standardmäßige und benutzerfreundliche Möglichkeit, die Multithreading-Funktionen von Node zu nutzen.
Bis zur Veröffentlichung von Node 10.5.0 stellte der Beamte ein experimentelles Modul worker_threads zur Verfügung, um Node mit echten Multithreading-Funktionen auszustatten.
Werfen wir zunächst einen Blick auf die einfache Demo:
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(); }
Der obige Code öffnet fünf Unterthreads im Hauptthread und der Hauptthread sendet einfache Nachrichten an die Unterthreads.
由于 worker_thread 目前仍然处于实验阶段,所以启动时需要增加 --experimental-worker
flag,运行后观察活动监视器:
不多不少,正好多了五个子线程。
worker_thread 核心代码
worker_thread 模块中有 4 个对象和 2 个类。
threadId === 0
进行判断的。来看一个进程通信的例子:
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(); }); }
更多详细用法可以查看官方文档。
根据大学课本上的说法:“进程是资源分配的最小单位,线程是CPU调度的最小单位”,这句话应付考试就够了,但是在实际工作中,我们还是要根据需求合理选择。
下面对比一下多线程与多进程:
属性 | 多进程 | 多线程 | 比较 |
---|---|---|---|
数据 | 数据共享复杂,需要用IPC;数据是分开的,同步简单 | 因为共享进程数据,数据共享简单,同步复杂 | 各有千秋 |
CPU、内存 | 占用内存多,切换复杂,CPU利用率低 | 占用内存少,切换简单,CPU利用率高 | 多线程更好 |
销毁、切换 | 创建销毁、切换复杂,速度慢 | 创建销毁、切换简单,速度很快 | 多线程更好 |
coding | 编码简单、调试方便 | 编码、调试复杂 | 多进程更好 |
可靠性 | 进程独立运行,不会相互影响 | 线程同呼吸共命运 | 多进程更好 |
分布式 | 可用于多机多核分布式,易于扩展 | 只能用于多核分布式 | 多进程更好 |
上述比较仅表示一般情况,并不绝对。
work_thread 让 Node 有了真正的多线程能力,算是不小的进步。
更多编程相关知识,请访问:编程视频!!
Das obige ist der detaillierte Inhalt vonEine kurze Diskussion über Multithread-Operationen in Nodejs. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!