Maison > interface Web > js tutoriel > Une brève discussion sur les opérations multithread dans Nodejs

Une brève discussion sur les opérations multithread dans Nodejs

青灯夜游
Libérer: 2021-06-24 11:28:19
avant
4519 Les gens l'ont consulté

Bien que nodejs soit monothread, il permet toujours des opérations multithreads. Cet article commencera par les threads Node, parlera des opérations multithread dans Nodejs et présentera le modèle worker_threads.

Une brève discussion sur les opérations multithread dans Nodejs

L'environnement de test pour cet article :
Système : macOS Mojave 10.14.2
CPU : 4 cœurs 2,3 GHz
Nœud : 10.15 .1

[Apprentissage recommandé : "Tutoriel Nodejs"]

Commencez avec les threads Node

La plupart des gens Comprendre Node Il est monothread, donc le nombre de threads devrait être de 1 après le démarrage de Node. Faisons une expérience pour voir. [Apprentissage recommandé : "tutoriel nodejs"]

setInterval(() => {
  console.log(new Date().getTime())
}, 3000)
Copier après la connexion

Une brève discussion sur les opérations multithread dans Nodejs

Vous pouvez voir que le processus Node occupe 7 threads. Pourquoi y a-t-il 7 sujets ?

Nous savons tous que le cœur de Node est le moteur v8. Après le démarrage de Node, une instance de v8 sera créée. Cette instance est multithread.

  • Thème principal : compiler et exécuter du code.
  • Thread de compilation/optimisation : Lorsque le thread principal s'exécute, le code peut être optimisé.
  • Fil de l'analyseur : enregistre le temps d'exécution du code d'analyse pour fournir une base à Crankshaft afin d'optimiser l'exécution du code.
  • Plusieurs fils de discussion pour le garbage collection.

Ainsi, quand les gens disent souvent que Node est monothread, cela signifie que l'exécution de JavaScript est monothread, mais que l'environnement hôte de Javascript, qu'il s'agisse de Node ou du navigateur, est multi -fileté.

Node dispose de deux compilateurs :
full-codegen : compilez simplement et rapidement js en un code mécanique simple mais lent.
Vilebrequin : un compilateur d'optimisation en temps réel relativement complexe qui compile du code exécutable hautes performances.

Certaines IO asynchrones occuperont des threads supplémentaires

Toujours avec l'exemple ci-dessus, on lit un fichier pendant que le timer s'exécute :

const fs = require('fs')

setInterval(() => {
    console.log(new Date().getTime())
}, 3000)

fs.readFile('./index.html', () => {})
Copier après la connexion

Une brève discussion sur les opérations multithread dans Nodejs

Le nombre de threads devient 11. En effet, il y a certaines opérations d'E/S (DNS, FS) et certains calculs gourmands en CPU (Zlib, Crypto) dans Node qui activent Node Le pool de threads, et la taille par défaut du pool de threads est de 4, car le nombre de threads devient 11.

Nous pouvons modifier manuellement la taille par défaut du pool de threads :

process.env.UV_THREADPOOL_SIZE = 64
Copier après la connexion

Changez facilement les threads en 71 avec une seule ligne de code.

Une brève discussion sur les opérations multithread dans Nodejs

Le cluster est-il multithread ?

Le thread unique de Node entraîne également certains problèmes, tels qu'une utilisation insuffisante du CPU, une exception non interceptée peut entraîner la fermeture de l'ensemble du programme, etc. Étant donné que le module cluster est fourni dans Node, le cluster implémente l'encapsulation de child_process et implémente le modèle multi-processus en créant des processus enfants via la méthode fork. Par exemple, pm2, que nous utilisons le plus souvent, est le meilleur représentant d’entre eux.

Regardons une démo de cluster :

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} 已启动`);
}
Copier après la connexion

À ce stade, regardez le moniteur d'activité :

Une brève discussion sur les opérations multithread dans Nodejs

Il y a 9 processus dans total, parmi lesquels Un processus principal, le nombre de CPU x le nombre de cœurs de CPU = 2 x 4 = 8 processus enfants.

Donc, ni child_process ni cluster ne sont un modèle multi-thread, mais un modèle multi-processus. Bien que les développeurs soient conscients des problèmes du modèle monothread, ils ne résolvent pas fondamentalement le problème et fournissent une méthode multi-processus pour simuler le multi-threading. D'après les expériences précédentes, nous pouvons voir que même si Node (V8) lui-même possède des capacités multithread, les développeurs ne peuvent pas faire bon usage de cette capacité. Au lieu de cela, ils utilisent d'une certaine manière le multithreading fourni par la couche inférieure de Node. Un responsable de Node a déclaré :

Vous pouvez utiliser le pool de travailleurs Node intégré en développant un module complémentaire C++. Sur les anciennes versions de Node, créez votre module complémentaire C++ à l'aide de NAN, et sur les versions plus récentes, utilisez N-API. . node-webworker-threads offre un moyen uniquement JavaScript d'accéder au pool de travailleurs de Node.

Mais pour les développeurs JavaScript, il n'y a jamais eu de moyen standard et facile à utiliser pour utiliser le multi-threads de Node. capacités de filetage.

Vrai - Node multi-threading

Jusqu'à la sortie de Node 10.5.0, le responsable fournissait un module expérimental worker_threads pour Node Fournit vrai capacités multithread.

Jetons d'abord un coup d'œil à la démo simple :

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();
}
Copier après la connexion

Le code ci-dessus ouvre cinq sous-threads dans le thread principal, et le thread principal envoie des messages simples aux sous-threads.

由于 worker_thread 目前仍然处于实验阶段,所以启动时需要增加 --experimental-worker flag,运行后观察活动监视器:

Une brève discussion sur les opérations multithread dans 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();
  });
}
Copier après la connexion

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

多进程 vs 多线程

根据大学课本上的说法:“进程是资源分配的最小单位,线程是CPU调度的最小单位”,这句话应付考试就够了,但是在实际工作中,我们还是要根据需求合理选择。

下面对比一下多线程与多进程:

属性 多进程 多线程 比较
数据 数据共享复杂,需要用IPC;数据是分开的,同步简单 因为共享进程数据,数据共享简单,同步复杂 各有千秋
CPU、内存 占用内存多,切换复杂,CPU利用率低 占用内存少,切换简单,CPU利用率高 多线程更好
销毁、切换 创建销毁、切换复杂,速度慢 创建销毁、切换简单,速度很快 多线程更好
coding 编码简单、调试方便 编码、调试复杂 多进程更好
可靠性 进程独立运行,不会相互影响 线程同呼吸共命运 多进程更好
分布式 可用于多机多核分布式,易于扩展 只能用于多核分布式 多进程更好

上述比较仅表示一般情况,并不绝对。

work_thread 让 Node 有了真正的多线程能力,算是不小的进步。

更多编程相关知识,请访问:编程视频!!

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:juejin.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal