Heim  >  Artikel  >  Web-Frontend  >  Eine kurze Diskussion über Multithread-Operationen in Nodejs

Eine kurze Diskussion über Multithread-Operationen in Nodejs

青灯夜游
青灯夜游nach vorne
2021-06-23 10:31:354507Durchsuche

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.

Eine kurze Diskussion über Multithread-Operationen in Nodejs

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“]

Apropos Node-Threads

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)

Eine kurze Diskussion über Multithread-Operationen in Nodejs

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.

  • Hauptthread: Code kompilieren und ausführen.
  • Kompilierungs-/Optimierungsthread: Wenn der Hauptthread ausgeführt wird, kann der Code optimiert werden.
  • Analysator-Thread: zeichnet die Codelaufzeit auf und analysiert sie, um eine Grundlage für die Optimierung der Codeausführung durch Crankshaft zu schaffen.
  • Mehrere Threads zur Müllsammlung.

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.

Einige asynchrone E/A belegen zusätzliche Threads

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', () => {})

Eine kurze Diskussion über Multithread-Operationen in Nodejs

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.

Eine kurze Diskussion über Multithread-Operationen in Nodejs

Ist der Cluster multithreaded?

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(&#39;exit&#39;, (worker, code, signal) => {
    console.log(`工作进程 ${worker.process.pid} 已退出`);
  });
} else {
  // 工作进程可以共享任何 TCP 连接。
  // 在本例子中,共享的是 HTTP 服务器。
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(&#39;Hello World&#39;);
  }).listen(8000);
  console.log(`工作进程 ${process.pid} 已启动`);
}

Sehen Sie sich zu diesem Zeitpunkt den Aktivitätsmonitor an:

Eine kurze Diskussion über Multithread-Operationen in Nodejs

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.

Richtig – Node-Multithreading

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(&#39;worker_threads&#39;);

function mainThread() {
  for (let i = 0; i < 5; i++) {
    const worker = new Worker(__filename, { workerData: i });
    worker.on(&#39;exit&#39;, code => { console.log(`main: worker stopped with exit code ${code}`); });
    worker.on(&#39;message&#39;, msg => {
      console.log(`main: receive ${msg}`);
      worker.postMessage(msg + 1);
    });
  }
}

function workerThread() {
  console.log(`worker: workerDate ${workerData}`);
  parentPort.on(&#39;message&#39;, 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,运行后观察活动监视器:

Eine kurze Diskussion über Multithread-Operationen in Nodejs

不多不少,正好多了五个子线程。

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(&#39;assert&#39;);
const {
  Worker,
  MessageChannel,
  MessagePort,
  isMainThread,
  parentPort
} = require(&#39;worker_threads&#39;);
if (isMainThread) {
  const worker = new Worker(__filename);
  const subChannel = new MessageChannel();
  worker.postMessage({ hereIsYourPort: subChannel.port1 }, [subChannel.port1]);
  subChannel.port2.on(&#39;message&#39;, (value) => {
    console.log(&#39;received:&#39;, value);
  });
} else {
  parentPort.once(&#39;message&#39;, (value) => {
    assert(value.hereIsYourPort instanceof MessagePort);
    value.hereIsYourPort.postMessage(&#39;the worker is sending this&#39;);
    value.hereIsYourPort.close();
  });
}

更多详细用法可以查看官方文档

多进程 vs 多线程

根据大学课本上的说法:“进程是资源分配的最小单位,线程是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!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.cn. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen