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.
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"]
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)
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.
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.
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', () => {})
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
Changez facilement les threads en 71 avec une seule ligne de code.
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('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} 已启动`); }
À ce stade, regardez le moniteur d'activité :
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.
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('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(); }
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,运行后观察活动监视器:
不多不少,正好多了五个子线程。
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 有了真正的多线程能力,算是不小的进步。
更多编程相关知识,请访问:编程视频!!
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!