part1
设为空字符串,part2
设为整个块 。如果part2
变得非常大--也许超过100,000个字符,因为没有回车符--将part2
追加到part1
,并将part2
设为空字符串 。这将确保被保存的部分不会无限地增长 。
part1
。part2
(它被添加到下一个块的开始) 。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
运行项目代码 。文章插图
你应该注意到了 , 基于
worker
的计算运行速度稍快,因为线程完全专用于该进程 。如果你的应用程序中遇到性能瓶颈,请考虑使用worker
。Child Processes有时需要调用那些不是用Node.js编写的或者有失败风险的应用程序 。
真实案例我写过一个Express应用程序,该程序生成了一个模糊的图像哈希值 , 用于识别类似的图形 。它以异步方式运行,并且运行良好,直到有人上传了一个包含循环引用的畸形GIF(动画帧A引用了帧B,而帧B引用了帧A) 。
推荐阅读
- 原神没有课题的答案任务是什么
- 平价好用的眼影有哪些?2018眼影排行榜十强
- 华为手机要恢复出厂设置的利弊(华为手机恢复出厂设置有问题吗)
- 赛马娘手游特雷森学院特别任务有哪些
- 红米note11和小米11有什么区别_哪款值得入手
- 怎样看电脑配置高低,决定电脑价格的因素有哪些
- 惠普星13air缺点_惠普星13air有哪些问题
- Java:既然有了synchronized,为什么还要提供Lock?
- 原神坎蒂丝天赋升级材料有哪些
- 四年级数学脱式计算题 四年级数学脱式计算题500道