Node.js 工作线程与子进程:应该使用哪一个

news2024/9/24 23:32:24

Node.js 工作线程与子进程:应该使用哪一个

并行处理在计算密集型应用程序中起着至关重要的作用。例如,考虑一个确定给定数字是否为素数的应用程序。如果我们熟悉素数,我们就会知道必须从 1 遍历到该数的平方根才能确定它是否是素数,而这通常非常耗时且计算量极大。

因此,如果我们在 Node.js 上构建此类计算量大的应用程序,我们可能会阻塞正在运行的线程很长时间。由于 Node.js 的单线程特性,不涉及 I/O 的计算密集型操作将导致应用程序停止,直到该任务完成。

因此,在构建需要执行此类任务的软件时,我们不会使用 Node.js。但是,Node.js 引入了工作线程 和子进程的概念 来帮助在 Node.js 应用程序中进行并行处理,以便我们可以并行执行特定进程。在本文中,我们将了解这两个概念并讨论何时使用它们。

Node.js 中的工作线程是什么

Node.js 能够有效地处理 I/O 操作。然而,当它遇到任何计算量大的操作时,它会导致主事件循环冻结。

在这里插入图片描述
当 Node.js 发现异步操作时,它将其“离岸”到线程池。但是,当它需要运行计算量大的操作时,它会在其主线程上执行该操作,这会导致应用程序阻塞,直到操作完成。因此,为了缓解这个问题,Node.js 引入了工作线程的概念,以帮助从主事件循环中卸载 CPU 密集型操作,以便开发人员可以以非阻塞方式并行生成多个线程。

它通过启动一个隔离的 Node.js 上下文来实现此目的,该上下文包含自己的 Node.js 运行时、事件循环和事件队列,该上下文在远程 V8 环境中运行。这在与主事件循环断开连接的环境中执行,从而允许主事件循环释放。

在这里插入图片描述
如上所示,Node.js 创建独立的运行时作为工作线程,其中每个线程独立于其他线程执行,并通过消息通道将其进程状态传达给父线程。这允许父线程继续照常执行其功能(不会被阻塞)。通过这样做,我们可以在 Node.js 中实现多线程。

在 Node.js 中使用工作线程有什么好处

正如我们所看到的,使用工作线程对于 CPU 密集型应用程序非常有益。事实上,它有几个优点:

  • 性能改进:我们可以将计算繁重的操作转移到工作线程,这可以释放主线程,从而使我们的应用程序能够响应更多请求。
  • 提高并行性:如果我们有一个大型进程,希望将其分成子任务并并行执行,则可以使用工作线程来执行此操作。例如,如果我们要确定 1,999,3241,123 是否为质数,则可以使用工作线程检查范围内的除数 -(WT1 中为 1 到 100,000,WT2 中为 100,001 到 200,000,等等)。这将加快我们的算法并导致更快的响应。

什么时候应该在 Node.js 中使用工作线程

如果我们考虑一下,我们应该只使用工作线程来运行与父线程隔离的计算密集型操作。

在工作线程中运行 I/O 操作是没有意义的,因为它们已经被转移到事件循环中。因此,当我们需要在隔离环境中执行计算量大的操作时,请考虑使用工作线程。

如何在 Node.js 中构建工作线程

如果所有这些听起来对我们很有吸引力,那么让我们看看如何在 Node.js 中实现工作线程。考虑下面的代码片段:

const {
  Worker,
  isMainThread,
  parentPort,
  workerData,
} = require("worker_threads");

const { generatePrimes } = require("./prime");

const threads = new Set();
const number = 999999;

const breakIntoParts = (number, threadCount = 1) => {
  const parts = [];
  const chunkSize = Math.ceil(number / threadCount);

  for (let i = 0; i < number; i += chunkSize) {
    const end = Math.min(i + chunkSize, number);
    parts.push({ start: i, end });
  }

  return parts;
};

if (isMainThread) {
  const parts = breakIntoParts(number, 5);
  parts.forEach((part) => {
    threads.add(
      new Worker(__filename, {
        workerData: {
          start: part.start,
          end: part.end,
        },
      })
    );
  });

  threads.forEach((thread) => {
    thread.on("error", (err) => {
      throw err;
    });
    thread.on("exit", () => {
      threads.delete(thread);
      console.log(`Thread exiting, ${threads.size} running...`);
    });
    thread.on("message", (msg) => {
      console.log(msg);
    });
  });
} else {
  const primes = generatePrimes(workerData.start, workerData.end);
  parentPort.postMessage(
    `Primes from - ${workerData.start} to ${workerData.end}: ${primes}`
  );
}

上面的代码片段展示了一个可以利用工作线程的理想场景。要构建工作线程,我们需要从库中导入Worker、IsMainThread、parentPort和 workerDataworker_threads 。这些定义将用于创建工作线程。

上面的代码创建了一种算法,可以查找给定范围内的所有素数。它将主线程中的范围分成不同的部分(上面示例中的五个部分),然后使用 new Worker() 来创建一个工作线程来处理每个部分。工作线程执行 else块,该块在分配给该工作线程的范围内查找素数,并最终使用 parentPort.postMessage() 将结果发送回父(主)线程。

Node.js 中的子进程是什么

子进程与工作线程不同。虽然工作线程在同一进程中提供隔离的事件循环和 V8 运行时,但子进程是整个 Node.js 运行时的单独实例。每个子进程都有自己的内存空间,并通过消息流或管道(或文件、数据库、TCP/UDP 等)等 IPC(进程间通信)技术与主进程进行通信。

在 Node.js 中使用子进程有什么好处

在 Node.js 应用程序中使用子进程会带来很多好处:

  • 改进的隔离性:每个子进程都在自己的内存空间中运行,提供与主进程的隔离。这对于可能存在资源冲突或需要分离的依赖性的任务是有利的。
  • 提高可扩展性:子进程在多个进程之间分配任务,这使我们可以利用多核系统并处理更多并发请求。
  • 提高鲁棒性:如果子进程由于某种原因崩溃,它不会随之崩溃我们的主进程。
  • 运行外部程序:子进程允许我们将外部程序或脚本作为单独的进程运行。这对于需要与其他可执行文件交互的场景非常有用。

什么时候应该在 Node.js 中使用子进程

所以,现在我们知道子进程给图片带来的好处了。了解何时应该在 Node.js 中使用子进程非常重要。根据我的经验,当我们想在 Node.js 中执行外部程序时,我建议我们使用子进程。

比如存在一种使用场景:我们必须从 Node.js 服务中运行外部可执行文件。不可能在主线程内执行二进制文件。因此,我们必须使用一个子进程来执行二进制文件。

如何在 Node.js 中构建子进程

在 Node.js 中创建子进程的方法有多种,可以使用 spawn() 、fork()、exec() 与 execFile() 等方法。

const { spawn } = require('child_process');
const child = spawn('node', ['child.js']);

child.stdout.on('data', (data) => {
  console.log(`Child process stdout: ${data}`);
});

child.on('close', (code) => {
  console.log(`Child process exited with code ${code}`);
});

我们所要做的就是从child_process模块导入一个 spawn() 方法,然后通过传递 CLI 参数作为参数来调用该方法。

如何在工作线程和子进程之间进行选择

现在我们知道什么是子进程和工作线程,那么了解何时使用这些技术很重要。它们都不是适合所有情况的灵丹妙药。这两种方法都适用于特定条件。

在以下情况下使用工作线程:

  • 我们正在运行 CPU 密集型任务。如果我们的任务是 CPU 密集型的,那么工作线程是一个不错的选择。
  • 我们的任务需要线程之间的共享内存和高效通信。工作线程具有对共享内存和用于通信的消息系统的内置支持。

在以下情况下使用子进程:

  • 我们正在运行需要隔离并独立运行的任务,特别是当它们涉及外部程序或脚本时。每个子进程都在自己的内存空间中运行。
  • 我们需要使用 IPC 机制(例如标准输入/输出流、消息传递或事件)在进程之间进行通信。子进程非常适合此目的。

总结

并行处理正在成为现代系统设计的一个重要方面,特别是在构建处理非常大的数据集或计算密集型任务的应用程序时。因此,在使用 Node.js 构建此类应用程序时,考虑工作线程和子进程非常重要。

如果我们的系统没有采用正确的并行处理技术进行正确设计,我们的系统可能会因过度耗尽资源而表现不佳(因为生成这些资源也会消耗大量资源)。

因此,对于软件工程师和架构师来说,清楚地验证需求并根据本文中提供的信息选择正确的工具非常重要。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1324405.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于YOLOv8的结核病预测系统设计与实现

一、项目背景 本系统的目的是通过痰液图像来检测出结核杆菌的携带者&#xff0c;及时采取治疗措施&#xff0c;在病情早期对其进行相关治疗减少结核病的传播。程序使用的样本是经过染色处理可以使得结核杆菌在显微镜拍摄的医学图像&#xff0c;通过检测医学图像中的结核杆菌诊…

ros2 学习03-开发工具vscode 插件配置

VSCode插件配置 为了便于后续ROS2的开发与调试&#xff0c;我们还可以安装一系列插件&#xff0c;无限扩展VSCode的功能。 中文语言包 Python插件 C插件 CMake插件 vscode-icons ROS插件 Msg Language Support Visual Studio IntelliCode URDF Markdown All in One VSCode支持的…

架构设计到底是什么?

文章目录 架构设计有哪些内容&#xff1f;架构原理与技术认知分布式技术原理与设计中间件常用组件的原理和设计问题数据库原理与设计问题分布式缓存原理与设计问题互联网高性能高可用设计问题 技术认知架构分析问题分析能力边界 架构设计&#xff0c;是中高级研发工程师逃不开的…

什么是集成测试?它和系统测试的区别是什么? 操作方法来了

01 什么是集成测试&#xff1f; 集成测试是软件测试的一种方法&#xff0c;用于测试不同的软件模块之间的交互和协作是否正常。集成测试的主要目的是确保不同的软件模块能够无缝协作&#xff0c;形成一个完整的软件系统&#xff0c;并且能够满足系统的需求和规格。 在集成测试…

理解pom.xml中的parent标签

✅作者简介&#xff1a;大家好&#xff0c;我是Leo&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Leo的博客 &#x1f49e;当前专栏&#xff1a; 循序渐进学SpringBoot ✨特色专栏&…

【设计模式--结构型--适配器模式】

设计模式--结构型--适配器模式 适配器模式概述结构案例类适配器模式对象适配器模式 应用场景 适配器模式 概述 将一个类的接口转换成客户希望的另一个接口&#xff0c;使得原本由于接口不兼容而不能一起工作的那些类能一起工作。 适配器模式分为类适配器模式和对象适配器模式…

《opencv实用探索·二十一》人脸识别

Haar级联分类器 在OpenCV中主要使用了两种特征&#xff08;即两种方法&#xff09;进行人脸检测&#xff0c;Haar特征和LBP特征。用的最多的是Haar特征人脸检测。 Haar级联分类器是一种用于目标检测的机器学习方法&#xff0c;它是一种基于机器学习的特征选择方法&#xff0c;…

如何下载知网论文、专利的PDF格式

知网的论文格式有其特有的格式&#xff1a;CAJ。将CAJ格式转化为Word或者PDF非常麻烦&#xff0c;且会出现乱码的情况&#xff0c;直接用知网官方的CAJ浏览器也不太方便。为此&#xff0c;困扰了许久。 其实&#xff0c;知网可以直接下载PDF格式&#xff0c;只需在浏览器上安装…

【halcon深度学习】create_dl_model_detection

基本介绍 create_dl_model_detection 不是一个封装的库函数&#xff0c;是一个算子。用于创建用于目标检测或实例分割任务的深度学习模型。 输入参数&#xff1a; Backbone (input_control): 指定用作背骨网络的深度学习分类器&#xff0c;充当模型的基础。用户可以选择不同的…

贝蒂快扫雷~(C语言)

✨✨欢迎大家来到贝蒂大讲堂✨✨ ​​​​&#x1f388;&#x1f388;养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;贝蒂的游戏 贝蒂的主页&#xff1a;Betty‘s blog 引言&#xff1a; 扫雷相信大家小时候到玩过吧&#xff0c;那…

【python】在线代码混淆方案及注意事项

▒ 目录 ▒ &#x1f6eb; 导读开发环境 1️⃣ 在线网站pyob混淆操作步骤编写测试代码混淆转pyc缺点中文路径问题&#xff1a;python: Cant reopen .pyc file 2️⃣ 反编译python文件格式对比uncompyle6 3️⃣ 其它方案cpythonpython-obfuscatorPyInstaller【不推荐】pyminifie…

内网穿透工具frp安装使用

摘要&#xff1a;之前使用的 nps 目前没有维护更新了&#xff0c;和在使用的过程中做内网穿透的的网速应该有限制&#xff0c;不论云服务器带宽是多少&#xff0c;下载速度都比较慢。这里切换到 frp 试试&#xff0c;对安装和使用简单记录&#xff0c;其和 nps 有很大的操作配置…

机器人也能干的更好:RPA技术的优势和应用场景

RPA是什么&#xff1f; 机器人流程自动化RPA&#xff08;Robotic Process Automation&#xff09;是一种自动化技术&#xff0c;它使用软件机器人来高效完成重复且有逻辑性的工作。近年来&#xff0c;随着人工智能和自动化技术的不断发展和普及&#xff0c;RPA已经成为企业提高…

流程挖掘技术在数字化转型中的应用价值

2023年2月27日国家正式发布了《数字中国建设整体布局规划》&#xff0c;指出建设数字中国是数字时代推进中国式现代化的重要引擎&#xff0c;是构筑国家竞争新优势的有力支撑&#xff0c;为加速数字化转型发出了明确号令。 随着数字化转型的推进&#xff0c;流程挖掘技术逐渐成…

CUMT--Java复习--异常

目录 一、异常 1、概述 2、异常处理机制 二、捕获异常 &#xff08;1&#xff09;try...catch语句 &#xff08;2&#xff09;try...catch..finally语句 &#xff08;3&#xff09;自动关闭资源的try语句 &#xff08;4&#xff09;其他 三、抛出异常 &#xff08;1&…

ICC2:illegal dimension route

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 illegal dimension route DRC的违例常出现的先进工艺里&#xff0c;部分层次在水平方向和竖直方向有宽度梯度的要求。如下示例: 意思就是竖直方向&#xff08;yLegalDim&#x…

yolov5障碍物识别-雪糕筒识别(代码+教程)

简介 这是一个检测交通锥并识别颜色的项目。我使用 yolov5 来训练和检测视锥细胞。此外&#xff0c;我使用 k 均值来确定主色&#xff0c;以对锥体颜色进行分类。目前&#xff0c;支持的颜色为红色、黄色、绿色和蓝色。其他颜色被归类为未知。 数据集和注释 我使用了一个自收…

会声会影2024永久汉化中文版本百度网盘下载

会声会影2024破解版免费下载是经过修改的视频剪辑软件&#xff0c;它能够免费为您提供很多功能。会声会影2024免费下载提供超过 1500 种独特的效果&#xff0c;可让您提升自我。会声会影破解版是用于是制作独一无二的视频的最强大、功能最全的软件。 它是一个简单而快速的视频编…

漏洞复现-log4j2原理分析及CVE-2021-44228

log4j2原理分析及漏洞复现 0x01 log4j2简介 Log4j2 是一个用于 Java 应用程序的成熟且功能强大的日志记录框架。它是 Log4j 的升级版本&#xff0c;相比于 Log4j&#xff0c;Log4j2 在性能、可靠性和灵活性方面都有显著的改进。 Log4j2 特点 高性能&#xff1a;Log4j2 使用异步…

JVM垃圾收集器三色标记算法

垃圾收集算法 分代收集理论 当前虚拟机的垃圾收集都采用分代收集算法&#xff0c;这种算法没有什么新的思想&#xff0c;只是根据对象存活周期的不同将内存分为几块。一般将java堆分为新生代和老年代&#xff0c;这样我们就可以根据各个年代的特点选择合适的垃圾收集算法。 比…