文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Node.js中Worker Threads的示例分析

2024-04-02 19:55

关注

这篇文章主要介绍了Node.js中Worker Threads的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

理解 Node 的底层对于理解 Workers 是很有必要的。

当一个 Node.js 的应用启动的同时,它会启动如下模块:

一个进程:process 对象是一个全局变量,可在 Node.js 程序中任意地方访问,并提供当前进程的相关信息。

一个线程:单线程意味着在当前进程中同一时刻只有一个指令在执行。

事件循环:这是 Node.js 中需要重点理解的一个部分,尽管 JavaScript 是单线程的,但通过使用回调,promises, async/await 等语法,基于事件循环将对操作系统的操作异步化,使得 Node 拥有异步非阻塞 IO 的特性。

一个 JS 引擎实例:即一个可以运行 JavaScript 代码的程序。

一个 Node.js 实例:即一个可以运行 Node.js 环境的程序。

换言之,Node 运行在单线程上,并且在事件循环中同一时刻只有一个进程的任务被执行,每次同一时刻只会执行一段代码(多段代码不会同时执行)。这是非常有效的,因为这样的机制足够简单,让你在使用 JavaScript 的时候无需担心并发编程的问题。

这样的原因在于 JavaScript 起初是用于客户端的交互(比如 web 页面的交互或表单的验证),这些逻辑并不需要多线程这样的机制来处理。

所以这也带来了另一个缺点:如果你需要使用 CPU 密集型的任务,比如在内存中使用一个大的数据集进行复杂计算,它会阻塞掉其他进程的任务。同样的,当你在发起一个有 CPU 密集型任务的远程接口请求时,也同样会阻塞掉其他需要被执行的请求。

如果一个函数阻塞了事件循环机制直到这个函数执行完才能执行下一个函数,那么它就被认为是一个阻塞型函数。一个非阻塞的函数是不会阻塞住事件循环进行下一个函数的执行的,它会使用回调通知事件循环函数任务已执行完毕。

最佳实践:不要阻塞事件循环,要让事件循环保持不断运行,并且注意避免使用回阻塞线程的操作比如同步的网络接口调用或死循环。

区分开 CPU 密集型操作与 I/O(input/output) 密集型操作是很重要的。像前面所说的,Node.js 并不会同时执行多段代码,只有 I/O 操作才会同时去执行,因为它们是异步的。

所以 Worker Threads 对于 I/O 密集型操作是没有太大的帮助的,因为异步的 I/O 操作比 worker 更有效率,Wokers 的主要作用是用于提升对于 CPU 密集型操作的性能。

其他方案

此外,目前已经存在很多对于 CPU 密集型操作的解决方案,比如多进程(cluster API)方案,保证了充分利用多核 CPU。

这个方案的好处在于进程之间是相互独立的,如果一个进程出现了问题,并不会影响到其他进程。此外它们还拥有稳定的 API,然而,这也意味着不能同享内存空间,而且进程间通信只能通过 JSON 格式的数据进行交互。

JavaScript 和 Node.js 不会有多线程,理由如下:

所以,人们可能会认为添加一个创建和同步线程的 Node.js 核心模块就可以解决 CPU 密集型操作的需求。

然而并不是,如果添加多线程模块,将会改变语言本身的特性。添加多线程模块作为可用的类或者函数是不可能的。在一些支持多线程的语言比如 Java 中,使用同步特性来使得多个线程之间的同步能够实现。

并且一些数字类型是不够原子性的,这意味着如果你不同步操作它们,在多线程的同时执行计算的情况下,变量的值可能会不断变动,没有确定的值,变量的值可能经过一个线程计算后改变了几个字节,在另一个线程计算后有改变了其他几个字节的数据。比如,在 JavaScript 中一些简单的计算像 0.1 + 0.2 的结果中小数部分有 17 位(小数的最高位数)。

var x = 0.1 + 0.2; // x will be 0.30000000000000004

但是浮点数的计算并不是 100% 精准的。所以如果不同步计算,小数部分的数字就会因为多个线程永远没有一个准确的数字。

最佳实践

所以解决 CPU 密集型操作的性能问题是使用 Worker Threads。浏览器在很久之前就已经有了 Workers 特性了。

单线程下的 Node.js:

多线程 Workers 下 Node.js 拥有:

就像下图:

Node.js中Worker Threads的示例分析

Worker_threads 模块允许使用多个线程来同时执行 JavaScript 代码。使用下面这个方式引入:

const worker = require('worker_threads');

Worker Threads 已经被添加到 Node.js 10 版本中,但是仍处于实验阶段。

使用 Worker threads 我们可以在在同一个进程内可以拥有多个 Node.js 实例,并且线程可以不需要跟随父进程的终止的时候才被终止,它可以在任意时刻被终止。当 Worker 线程销毁的时候分配给该 Worker 线程的资源依然没有被释放是一个很不好的操作,这会导致内存泄漏问题,我们也不希望这样。我们希望这些分配资源能够嵌入到 Node.js 中,让 Node.js 有创建线程的能力,并且在线程中创建一个新的 Node.js 实例,本质上就像是在同一个进程中运行多个独立的线程。

Worker Threads 有如下特性:

API:

例子

const { Worker } = require('worker_threads');

const worker = new Worker(`
const { parentPort } = require('worker_threads');
parentPort.once('message',
    message => parentPort.postMessage({ pong: message }));  
`, { eval: true });
worker.on('message', message => console.log(message));      
worker.postMessage('ping');
$ node --experimental-worker test.js
{ pong: ‘ping’ }

上面例子所做的也就是使用 new Worker 创建一个线程,线程中的代码监听了 parentPort 的消息,并且当接收到数据的时候只触发一次回调,将收到的数据传输回父进程中。

你需要使用 --experimental-worker 启动程序因为 Workers 还在实验阶段。

另一个例子:

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));
}

上面代码中:

在实际使用中,应该使用线程池的方式,不然不断地创建 worker 线程的代价将会超过它带来的好处。

对于 Worker 的使用建议:

对于 Worker 的一些不好的想法:

最后

Chrome devTools 支持 Node.js 中的 Workers 线程特性。worker_threads 是一个实验模块,如果你需要在 Node.js 中运行 CPU 密集型的操作,目前不建议在生产环境中使用 worker 线程,可以使用进程池的方式来代替。

感谢你能够认真阅读完这篇文章,希望小编分享的“Node.js中Worker Threads的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持编程网,关注编程网行业资讯频道,更多相关知识等着你来学习!

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-前端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯