Cet article vous fera découvrir le module worker_threads, vous présentera comment utiliser worker_threads pour implémenter le multi-threading dans Node et utiliser worker_threads pour exécuter la séquence de Fibonacci comme exemple pratique. J'espère que cela sera utile à tout le monde !
Normalement, Node.js
Node.js
被认为是单线程。由主线程去按照编码顺序一步步执行程序代码,一旦遇到同步代码阻塞,主线程就会被占用,后续的程序代码的执行都会被卡住。没错Node.js
的单线程指的是主线程是"单线程"。
为了解决单线程带来的问题,本文的主角worker_threads
出现了。worker_threads
首次在Node.js v10.5.0
作为实验性功能出现,需要命令行带上--experimental-worker
才能使用。直到v12.11.0
稳定版才能正式使用。
本文将会介绍worker_threads
的使用方式,以及利用worker_threads
执行斐波那契数列作为实践例子。
阅读并食用本文,需要先具备:
Node.js v12.11.0
及以上版本worker_threads
模块允许使用并行执行 JavaScript 的线程。
工作线程对于执行 CPU 密集型的 JavaScript 操作很有用。 它们对 I/O 密集型的工作帮助不大。 Node.js 内置的异步 I/O 操作比工作线程更高效。
与 child_process
或 cluster
不同,worker_threads
可以共享内存。 它们通过传输 ArrayBuffer
实例或共享 SharedArrayBuffer
实例来实现。
由于以下特性,worker_threads
已被证明是充分利用CPU性能的最佳解决方案:
它们运行具有多个线程的单个进程。
每个线程执行一个事件循环。
每个线程运行单个 JS 引擎实例。
每个线程执行单个 Nodejs 实例。
worker_threads
通过执行主线程
指定的脚本文件
来工作。每个线程都在与其他线程隔离的情况下执行。但是,这些线程可以通过消息通道来回传递消息。
主线程
使用worker.postMessage()
函数使用消息通道,而工作线程
使用parentPort.postMessage()
函数。
通过官方示例代码加强了解:
const { Worker, isMainThread, parentPort, workerData } = require('worker_threads'); if (isMainThread) { module.exports = function parseJSAsync(script) { return new Promise((resolve, reject) => { const worker = new Worker(__filename, { workerData: script }); worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) reject(new Error(`Worker stopped with exit code ${code}`)); }); }); }; } else { const { parse } = require('some-js-parsing-library'); const script = workerData; parentPort.postMessage(parse(script)); }
上述代码主线程
与工作线程
都使用同一份文件作为执行脚本(__filename
为当前执行文件路径),通过isMainThread
来区分主线程
与工作线程
运行时逻辑。当模块对外暴露方法parseJSAsync
被调用时候,都将会衍生子工作线程去执行调用parse
函数。
在本节使用具体例子介绍worker_threads
的使用
创建工作线程
脚本文件workerExample.js
:
const { workerData, parentPort } = require('worker_threads') parentPort.postMessage({ welcome: workerData })
创建主线程
脚本文件main.js
:
const { Worker } = require('worker_threads') const runWorker = (workerData) => { return new Promise((resolve, reject) => { // 引入 workerExample.js `工作线程`脚本文件 const worker = new Worker('./workerExample.js', { workerData }); worker.on('message', resolve); worker.on('error', reject); worker.on('exit', (code) => { if (code !== 0) reject(new Error(`stopped with ${code} exit code`)); }) }) } const main = async () => { const result = await runWorker('hello worker threads') console.log(result); } main().catch(err => console.error(err))
控制台命令行执行:
node main.js
输出:
{ welcome: 'hello worker threads' }
在本节中,让我们看一下 CPU 密集型示例,生成斐波那契数列。
如果在没有工作线程的情况下完成此任务,则会随着nth
期限的增加而阻塞主线程。
创建工作线程
脚本文件worker.js
const {parentPort, workerData} = require("worker_threads"); parentPort.postMessage(getFibonacciNumber(workerData.num)) function getFibonacciNumber(num) { if (num === 0) { return 0; } else if (num === 1) { return 1; } else { return getFibonacciNumber(num - 1) + getFibonacciNumber(num - 2); } }
创建主线程
脚本文件main.js
:
const {Worker} = require("worker_threads"); let number = 30; const worker = new Worker("./worker.js", {workerData: {num: number}}); worker.once("message", result => { console.log(`${number}th Fibonacci Result: ${result}`); }); worker.on("error", error => { console.log(error); }); worker.on("exit", exitCode => { console.log(`It exited with code ${exitCode}`); }) console.log("Execution in main thread");
控制台命令行执行:
node main.js
输出:
Execution in main thread 30th Fibonacci Result: 832040 It exited with code 0
在main.js
文件中,我们从类的实例创建一个工作线程,Worker
est considéré comme monothread. Le thread principal exécute le code du programme étape par étape selon la séquence de codage. Une fois le code de synchronisation bloqué, le thread principal sera occupé et l'exécution ultérieure du code du programme sera bloquée. C'est vrai, le thread unique de Node.js
signifie que le thread principal est "à thread unique".
Afin de résoudre les problèmes causés par un seul thread, le protagoniste de cet article worker_threads
apparaît. worker_threads
est apparu pour la première fois en tant que fonctionnalité expérimentale dans Node.js v10.5.0
et nécessite --experimental-worker
sur la ligne de commande pour l'utiliser. Il ne peut pas être officiellement utilisé avant la version stable v12.11.0
.
worker_threads
et comment utiliser worker_threads
pour exécuter Séquence de Fibonacci 🎜 comme exemple pratique. 🎜Node.js v12.11.0
et versions supérieuresworker_threads
permet l'utilisation de threads qui exécutent du JavaScript dans parallèle. 🎜🎜Les threads de travail sont utiles pour effectuer des opérations JavaScript gourmandes en CPU. Ils ne sont pas très utiles pour les travaux intensifs en E/S. Les opérations d'E/S asynchrones intégrées de Node.js sont plus efficaces que les threads de travail. 🎜🎜Contrairement à child_process
ou cluster
, worker_threads
peut partager la mémoire. Pour ce faire, ils transfèrent des instances ArrayBuffer
ou partagent des instances SharedArrayBuffer
. 🎜🎜Les worker_threads
se sont avérés être la meilleure solution pour utiliser pleinement les performances du processeur grâce aux propriétés suivantes : 🎜worker_threads
en exécutant le spécifié par le <code>thread principal< /code> >fichier de script
pour fonctionner. Chaque thread s'exécute indépendamment des autres threads. Cependant, ces fils de discussion peuvent transmettre des messages via des canaux de messagerie. 🎜🎜Main thread
utilise la fonction worker.postMessage()
pour utiliser le canal de message, tandis que worker thread
utilise parentPort.postMessage( )
code> fonction. 🎜🎜Améliorez votre compréhension grâce à l'exemple de code officiel : 🎜console.log("Execution in main thread");
thème principal
et les Threads de travail
utilisent tous le même fichier que le script d'exécution (__filename
est le chemin du fichier d'exécution actuel), et le thread principal
se distingue par < code>isMainThread > Logique d'exécution avec threads de travail
. Lorsque la méthode parseJSAsync
exposée en externe du module est appelée, un thread sous-travailleur sera généré pour exécuter la fonction parse
. 🎜worker_threads
🎜🎜Créer un worker thread</ code> fichier de script <code>workerExample.js
:🎜rrreee🎜Créer un thread principal
fichier de script main.js
:🎜rrreee🎜Exécution de la ligne de commande de la console :🎜 rrreee🎜output :🎜rrreeeénième
délai augmente. 🎜🎜Créez le fichier de script thread de travail
worker.js
🎜rrreee🎜Créez le fichier de script thread principal
main.js
: 🎜rrreee🎜Exécution de la ligne de commande de la console : 🎜rrreee🎜Sortie : 🎜rrreee🎜Dans le fichier main.js
, nous créons un thread de travail à partir d'une instance de la classe, Worker
comme nous l'avons vu dans l'exemple précédent. 🎜🎜Afin d'obtenir les résultats, nous écoutons 3 événements, 🎜message
响应工作线程
发出消息。exit
在工作线程
停止执行的情况下触发的事件。error
发生错误时触发。我们在最后一行main.js
,
console.log("Execution in main thread");
通过控制台的输出可得,主线程
并没有被斐波那契数列运算执行而阻塞。
因此,只要在工作线程
中处理 CPU 密集型任务,我们就可以继续处理其他任务而不必担心阻塞主线程。
Node.js
在处理 CPU 密集型任务时一直因其性能而受到批评。通过有效地解决这些缺点,工作线程的引入提高了 Node.js 的功能。
有关worker_threads
的更多信息,请在此处访问其官方文档。
文章结束前留下思考,后续会在评论区做补充,欢迎一起讨论。
worker_threads
线程空闲时候会被回收吗?worker_threads
共享内存如何使用?线程
,那么应该有线程池
?更多node相关知识,请访问:nodejs 教程!
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!