当前位置: 首页 > news >正文

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

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 构建此类应用程序时,考虑工作线程和子进程非常重要。

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

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

相关文章:

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

Node.js 工作线程与子进程&#xff1a;应该使用哪一个 并行处理在计算密集型应用程序中起着至关重要的作用。例如&#xff0c;考虑一个确定给定数字是否为素数的应用程序。如果我们熟悉素数&#xff0c;我们就会知道必须从 1 遍历到该数的平方根才能确定它是否是素数&#xff…...

python matplotlib 三维图形添加文字且不随图形变动而变动

要在三维图形中添加文字并使其不随图形变动而变动&#xff0c;可以使用 annotate() 方法。这个方法可以在三维图形中添加文字&#xff0c;并且可以指定文字的位置、对齐方式和字体大小等属性。 下面是一个示例代码&#xff0c;演示如何在三维图形中添加文字&#xff1a; impo…...

Ubuntu设置kubelet启动脚本关闭swap分区

查看swap分区 swapon -s打开swap分区 swapon -a查看/etc/fstab下所有固化的swap分区&#xff0c;注释 vi /etc/fstab修改kubelet.conf文件 vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf添加 ExecStartPre/sbin/swapoff -a生效 systemctl daemon-reload sys…...

MySQL数据库存储

MySQL数据库存储 MySQL数据库简介MySQL开发环境MySQL安装图形化界面工具Navicat使用 表的操作表的概念3.2 创建表3.3 修改表 数据的操作-增删改查4.1 增加数据4.2 删除数据4.3 修改数据4.4 查询数据4.4.1 基础查询4.4.2 分组查询和聚合函数4.4.4 having语句4.4.5 排序4.5 多表联…...

verilog语法进阶,时钟原语

概述&#xff1a; 内容 1. 时钟缓冲 2. 输入时钟缓冲 3. ODDR2作为输出时钟缓冲 1. 输入时钟缓冲 BUFGP verilog c代码&#xff0c;clk作为触发器的边沿触发&#xff0c;会自动将clk综合成时钟信号。 module primitive1(input clk,input a,output reg y); always (posed…...

案例069:基于微信小程序的计算机实验室排课与查询系统

文末获取源码 开发语言&#xff1a;Java 框架&#xff1a;SSM JDK版本&#xff1a;JDK1.8 数据库&#xff1a;mysql 5.7 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;Maven3.5.4 小程序框架&#xff1a;uniapp 小程序开发软件&#xff1a;HBuilder X 小程序…...

C语言:将三个数从大到小输出

#include<stdio.h> int main() {int a 0;int b 0;int c 0;printf("请输入abc的值&#xff1a;");scanf_s("%d%d%d", &a, &b, &c);if (b > a){int tmp a;a b;b tmp;}if (c > a){int tmp a;a c;c tmp;}if (b < c){int t…...

基于Hadoop的铁路货运大数据平台设计与应用

完整下载&#xff1a;基于Hadoop的铁路货运大数据平台设计与应用 基于Hadoop的铁路货运大数据平台设计与应用 Design and Application of Railway Freight Big Data Platform based on Hadoop 目录 目录 2 摘要 3 关键词 4 第一章 绪论 4 1.1 研究背景 4 1.2 研究目的与意义 5 …...

Java基础题2:类和对象

1.下面代码的运行结果是&#xff08;&#xff09; public static void main(String[] args){String s;System.out.println("s"s);}A.代码编程成功&#xff0c;并输出”s” B.代码编译成功&#xff0c;并输出”snull” C.由于String s没有初始化&#xff0c;代码不能…...

冒泡排序学习

冒泡排序&#xff08;Bubble Sort&#xff09;是一种简单的排序算法&#xff0c;它通过重复地交换相邻的元素来排序。具体实现如下&#xff1a; 1. 从待排序的数组中的第一个元素开始&#xff0c;依次比较相邻的两个元素。 2. 如果前一个元素大于后一个元素&#xff0c;则交换…...

LeetCode(65)LRU 缓存【链表】【中等】

目录 1.题目2.答案3.提交结果截图 链接&#xff1a; LRU 缓存 1.题目 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 k…...

网站提示“不安全”

当你在浏览网站时&#xff0c;有时可能会遇到浏览器提示网站不安全的情况。这通常是由于网站缺乏SSL证书所致。那么&#xff0c;从SSL证书的角度出发&#xff0c;我们应该如何解决这个问题呢&#xff1f; 首先&#xff0c;让我们简单了解一下SSL证书。SSL证书是一种用于保护网站…...

【Linux】驱动

驱动 驱动程序过程 系统调用 用户空间 内核空间 添加驱动和调用驱动 驱动程序是如何调用设备硬件 驱动 在计算机领域&#xff0c;驱动&#xff08;Driver&#xff09;是一种软件&#xff0c;它充当硬件设备与操作系统之间的桥梁&#xff0c;允许它们进行通信和协同工作。驱动程…...

Java研学-HTML

HTML 1 介绍 HTML(Hypertext Markup Language) 超文本标记语言。静态网页&#xff0c;用于在浏览器上显示数据 超文本: 指页面内可以包含图片、链接&#xff0c;甚至音乐、程序等非文字元素。 标记语言: 使用 < > 括起来的语言 超文本标记语言的结构, 包括“头”部分&am…...

SpringBoot之响应的详细解析

2. 响应 前面我们学习过HTTL协议的交互方式&#xff1a;请求响应模式&#xff08;有请求就有响应&#xff09; 那么Controller程序呢&#xff0c;除了接收请求外&#xff0c;还可以进行响应。 2.1 ResponseBody 在我们前面所编写的controller方法中&#xff0c;都已经设置了…...

redis:四、双写一致性的原理和解决方案(延时双删、分布式锁、异步通知MQ/canal)、面试回答模板

双写一致性 场景导入 如果现在有个数据要更新&#xff0c;是先删除缓存&#xff0c;还是先操作数据库呢&#xff1f;当多个线程同时进行访问数据的操作&#xff0c;又是什么情况呢&#xff1f; 以先删除缓存&#xff0c;再操作数据库为例 多个线程运行的正常的流程应该如下…...

智能优化算法应用:基于动物迁徙算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于动物迁徙算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于动物迁徙算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.动物迁徙算法4.实验参数设定5.算法结果6.…...

illuminate/database 使用 五

之前文章&#xff1a; illuminate/database 使用 一-CSDN博客 illuminate/database 使用 二-CSDN博客 illuminate/database 使用 三-CSDN博客 illuminate/database 使用 四-CSDN博客 一、原生查询 1.1 原理 根据之前内容调用执行的静态类为Illuminate\Database\Capsule\M…...

武汉灰京文化:益智游戏的教育与娱乐完美结合

随着游戏技术的不断发展&#xff0c;益智类游戏正经历着一场革命性的变革&#xff0c;逐渐融合了教育和娱乐的元素。创新的设计和互动方式使得许多益智游戏成为了知识传递和技能训练的有效工具&#xff0c;同时保持了娱乐体验的趣味性。这种教育与娱乐的完美结合不仅使益智游戏…...

arcgis api for js 中的query实现数据查询

相当于服务地址中的query查询 获取图层范围内的数据4.24 import Query from arcgis/core/rest/support/Query; import * as QueryTask from "arcgis/core/rest/query";//获取图层范围内的数据4.24 _returnFeatureFromWhere(url, where, geo) {const self thisretu…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

dedecms 织梦自定义表单留言增加ajax验证码功能

增加ajax功能模块&#xff0c;用户不点击提交按钮&#xff0c;只要输入框失去焦点&#xff0c;就会提前提示验证码是否正确。 一&#xff0c;模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...

AI病理诊断七剑下天山,医疗未来触手可及

一、病理诊断困局&#xff1a;刀尖上的医学艺术 1.1 金标准背后的隐痛 病理诊断被誉为"诊断的诊断"&#xff0c;医生需通过显微镜观察组织切片&#xff0c;在细胞迷宫中捕捉癌变信号。某省病理质控报告显示&#xff0c;基层医院误诊率达12%-15%&#xff0c;专家会诊…...

Java求职者面试指南:Spring、Spring Boot、MyBatis框架与计算机基础问题解析

Java求职者面试指南&#xff1a;Spring、Spring Boot、MyBatis框架与计算机基础问题解析 一、第一轮提问&#xff08;基础概念问题&#xff09; 1. 请解释Spring框架的核心容器是什么&#xff1f;它在Spring中起到什么作用&#xff1f; Spring框架的核心容器是IoC容器&#…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

作为测试我们应该关注redis哪些方面

1、功能测试 数据结构操作&#xff1a;验证字符串、列表、哈希、集合和有序的基本操作是否正确 持久化&#xff1a;测试aof和aof持久化机制&#xff0c;确保数据在开启后正确恢复。 事务&#xff1a;检查事务的原子性和回滚机制。 发布订阅&#xff1a;确保消息正确传递。 2、性…...

解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用

在工业制造领域&#xff0c;无损检测&#xff08;NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统&#xff0c;以非接触式光学麦克风技术为核心&#xff0c;打破传统检测瓶颈&#xff0c;为半导体、航空航天、汽车制造等行业提供了高灵敏…...

flow_controllers

关键点&#xff1a; 流控制器类型&#xff1a; 同步&#xff08;Sync&#xff09;&#xff1a;发布操作会阻塞&#xff0c;直到数据被确认发送。异步&#xff08;Async&#xff09;&#xff1a;发布操作非阻塞&#xff0c;数据发送由后台线程处理。纯同步&#xff08;PureSync…...