Worker Threads官方文档是这么说的:Workers(线程)对于执行CPU密集型的JavaScript操作很有用 。它们对I/O密集型的工作帮助不大 。Node.js内置的异步I/O操作比Workers的效率更高 。
假设一个用户可以在你的Express应用程序中触发一个复杂的、十秒钟的JavaScript计算 。该计算将成为一个瓶颈,使所有用户的处理程序停止 。你的应用程序不能处理任何请求或运行其他功能,除非它计算完成 。
异步计算处理来自文件或数据库数据的复杂计算可能问题不大,因为每个阶段在等待数据到达时都是异步运行 。数据处理发生在事件循环的不同迭代中 。
然而,仅用JavaScript编写的长运行计算,比如图像处理或机器学习算法,将占用事件循环的当前迭代 。
一种解决方案就是worker线程 。这类似于浏览器的web worker以及在独立线程上启动JavaScript进程 。主线程和worker线程可以交换信息来触发或者终止程序 。
Workers和事件循环Workers对CPU密集型JavaScript操作很有用,尽管Node.js的主事件循环仍应用于异步I/O活动 。
示例代码有一个worker项目,其在lib/dice.js
中导出diceRun()
函数 。这是将任意数量的N面骰子投掷若干次,并记录总分的计数(应该是正态分布曲线的结果):
// dice throwingexport function diceRun(runs = 1, dice = 2, sides = 6) {const stat = [];while (runs > 0) {let sum = 0;for (let d = dice; d > 0; d--) {sum += Math.floor( Math.random() * sides ) + 1;}stat[sum] = (stat[sum] || 0) + 1;runs--;}return stat;}
index.js
中的代码启动一个进程,每秒钟运行一次并输出一条信息:
// run process every secondconst timer = setInterval(() => {console.log('another process');}, 1000);
调用diceRun()
函数,将两个骰子抛出10亿次:
import { diceRun } from './lib/dice.js';// throw 2 dice 1 billion timesconstnumberOfDice = 2,runs = 999_999_999;const stat1 = diceRun(runs, numberOfDice);
这将暂停计时器,因为Node.js事件循环在计算完成之前不能继续下一次迭代 。
然后,将上述代码在一个新的Worker
中尝试相同的计算 。这会加载一个名为worker.js
的脚本,并在配置对象上的workerData
属性传递计算参数:
import { Worker } from 'worker_threads';const worker = new Worker('./worker.js', { workerData: { runs, numberOfDice } });
事件处理器被附加到运行worker.js
脚本的worker
对象上,以便它能接收传入的结果:
// result returnedworker.on('message', result => {console.table(result);});
以及处理错误:
// worker errorworker.on('error', e => {console.log(e);});
以及在处理完成后进行整理:
// worker completeworker.on('exit', code => {// tidy up});
worker.js
脚本启动diceRun()
计算,并在计算完成后向父脚本发布一条消息--该消息由上面的message
处理器接收:
// worker threadimport { workerData, parentPort } from 'worker_threads';import { diceRun } from './lib/dice.js';// worker threadimport { workerData, parentPort } from 'worker_threads';import { diceRun } from './lib/dice.js';// start calculationconst stat = diceRun( workerData.runs, workerData.numberOfDice );// post message to parent scriptparentPort.postMessage( stat );
在worker
运行时,计时器并没有暂停,因为它是在另一个CPU线程上执行的 。换句话说,Node.js的事件循环继续迭代,而没有长延迟 。
使用node index.js
运行项目代码 。

文章插图
你应该注意到了,基于
经验总结扩展阅读
- 飞机上可以带辣椒酱吗
- 经济价值高的树种有哪些 世界十大经济树木排名榜
- 可乐鸡翅没有料酒可以用什么代替
- 芒果皮有毒吗
- 原神没有课题的答案任务是什么
- 冰箱里一定有李斯特菌吗
- 学蛋糕甜点适合在哪里学
- 3.5l的砂锅有多大
- 冻干免煮银耳羹还有营养吗?
- 红葱头的吃法