Node.js 中的多线程和多进程 nodejs多线程还是单线程
lipiwang 2024-11-04 14:36 37 浏览 0 评论
作者:疯狂的技术宅 来源:前端先锋
Node.js 是一个免费的跨平台 JavaScript 运行时环境,尽管它本质上是单线程的,但是可以在后台使用多个线程来执行异步代码。
由于 Node.js 的非阻塞性质,不同的线程执行不同的回调,这些回调首先委托给事件循环。Node.js 运行时负责处理所有这一切。
为什么要用 NodeJS?
JavaScript 最初是作为一种单线程编程语言构建的,仅在 Web 浏览器中运行。这意味着在一个过程中,只有一组指令能够在给定的时间执行。
仅在当前代码块的执行完成后,才移至下一个代码块。但是,JavaScript 的单线程性质使实现变得容易。
最初 JavaScript 仅用于向网站添加少量交互。所以并没有对多线程的需求。但是时代已经变了,用户要求也越来越高,JavaScript 已成为 Web 上流行的编程语言。
多线程现在变得很普遍。由于 JavaScript 是单线程语言,因此无法在其中实现多线程。幸运的是,在这种情况下,有一个很好的解决方法:Node.js。
Node.js 框架并不少,这要归功于 JavaScript 运行时环境(尤其是 JavaScript)的普遍流行。在继续本文之前,让我们了解一些有关 Node.js 的重要观点:
- 可以用 send 函数将消息从子进程传递到其他子进程和主进程
- 支持 fork 多个进程
- 主进程和子进程之间不共享状态
为什么要 fork 进程?
在两种情况下,我们需要 fork 一个流程:
- 通过将任务委派给其他进程来提高速度
- 用于释放内存和卸载单个进程
可以将数据发送到子进程,也可以将其送回。
Node.js 的方式
Node.js 使用两种类型的线程:
- 通过事件循环处理主线程,
- 工作池中有许多辅助线程
事件循环负责获取回调或函数,并将其注册以供将来执行。它与正确的 JavaScript 代码在同一线程中运行。一旦 JavaScript 操作阻塞了线程,事件循环也会被阻塞。
工作池是一个执行模型,负责产生和处理不同的线程。它同步执行任务,然后将结果返回到事件循环,最后事件循环将结果提供给回调。
总而言之,工作池负责异步 I/O 操作,即与系统磁盘和网络的交互。像 fs 和 crypto 这样的模块是使用工作池的主要模块。
由于工作池是在 libuv 库中实现的,Node.js 在 JS 和 C++ 之间进行内部通信时会稍有延迟。不过这几乎是不可察觉的。
一切都很好,直到我们遇到同步执行复杂操作的要求。任何需要大量时间执行的函数都会导致主线程阻塞。
如果程序具有多个占用大量 CPU 的函数,将会导致服务器吞吐量地显著下降。在最坏的情况下,服务器将会失去响应,并且无法将任务委派给工作池。
诸如 AI、大数据和机器学习之类的领域无法从 Node.js 中受益,因为这些操作阻塞了主线程,并使服务器失去响应。但是这随着 Node.js v10.5.0 的到来而改变,该版本增加了对多线程的支持。
并发和 CPU 绑定任务的挑战
在 JavaScript 中建立并发可能很困难。允许多个线程访问相同的内存会导致竞争状态,这不仅使故障难以重现,而且解决起来也很困难。
Node.js 最初被实现为基于异步 I/O 的服务器端平台。通过简单地消除线程需求,这使很多事情变得容易。是的,Node.js 程序是单线程的,但不是典型的方式。
我们可以在 Node.js 中并行运行,但是不需要创建线程。操作系统和虚拟机共同并行使用 I/O,然后在需要将数据发送回 JavaScript 代码时,JS 代码在单个线程中运行。
除 JS 代码外,所有内容均在 Node.js 中并行运行。与异步块不同,JS 的同步块总是一次执行一次。与代码执行相比,等待 JS 中产生 I/O 事件所花费的时间要多得多。
Node.js 程序仅调用所需的函数或回调,而不会阻止其他代码的执行。最初 JavaScript 和 Node.js 都不打算处理 CPU 密集型或 CPU 绑定的任务。
当代码最少时,执行将会是敏捷的。但是计算量越大,执行速度就越慢。
如果你仍然尝试在 JS 和 Node 中完成 CPU 密集型任务,那么将会使浏览器中的 UI 冻结并对所有 I/O 事件进行排队处理。尽管如此,我们已经走了很远。现在有了 worker_threads 模块。
worker_threads 模块使多线程变得简单
Node.js v10.5.0 于 2018 年 6 月发布,引入了 worker_threads 模块。它有助于在流行的 JavaScript 运行时环境中实现并发。该模块允许创建功能齐全的多线程 Node.js 应用。
从技术上讲,工作线程是在单独的线程中产生的一些代码。要开始使用辅助线程,需要先导入 worker_threads 模块。之后需要创建 Worker 类的实例以创建工作线程。
创建 Worker 类的实例时,有两个参数:
- 第一个参数提供扩展名 .js 或 .mjs 的文件路径,其中包含工作程序线程的代码,
- 第二个参数提供了一个包含 workerData 属性的对象,该属性包含工作线程开始执行时将访问的数据
辅助线程能够调度多个消息事件。因此,回调方法优先于返回 promise。
工作线程之间的通信是基于事件的,即侦听器设置为在工作线程发送事件后立即调用。最常见的 4 个事件是:
worker.on('error', (error) => {});
(1) 当工作线程中有未捕获的异常时发出。接下来工作线程终止,并且该错误可以作为回调中的第一个参数使用。
worker.on('exit', (exitCode) => {})
(2) 当辅助线程退出时发出。如果在工作线程中调用了 process.exit(),则会将 exitCode 提供给回调。如果 worker.terminate() 终止工作线程,则代码为 1。
worker.on('message', (data) => {});
(3) 当工作线程将数据发送到父线程时发出。
worker.on('online', () => {});
(4) 当工作线程停止解析 JS 代码并开始执行时发出。尽管不常用,但 online 事件在特定情况下可能会提供更多信息。
使用工作线程的方式
有两种使用工作线程的方法:
- 方法 1 – 涉及产生工作线程,执行其代码并将结果发送到父线程。此方法需要每次为新任务从头创建新的 worker 线程。
- 方法 2 – 涉及生成 worker 线程并为消息事件设置侦听器。每次触发该消息时,辅助线程都会执行代码,并将结果发送回父线程。辅助线程保持活动状态,以备将来使用。
方法 2 也被称为工作池。这是因为该方法涉及创建 worker 的工作池,先让他们等待,并在需要时去调度消息事件来执行任务。
由于从头创建工作线程需要创建虚拟机以及解析和执行代码,因此官方 Node.js 文档 建议采用方法 2。此外,方法 2 更为实用,比方法 1 更有效。
(1) worker_threads 模块中可用的重要属性
- isMainThread – 当不在工作线程内操作时,此属性为 true。如果需要,则可以在 worker 文件的开头包含一个简单的 if 语句。这样可以确保它仅作为工作线程运行。
- parentPort – MessagePort 的实例,用于与父线程进行通信。
- threadId – 分配给工作线程的唯一标识符。
- workerData – 包含在 worker 线程的构造函数中的数据。
(2) Node.js 中的多进程
为了使 Node.js 利用多核系统的功能,可以用一些进程。流行的 javascript 运行时环境中有称被为 cluster 的模块,该模块提供对多进程的支持。
使用 cluster 模块可以产生多个子进程,这些子进程可以共享一个公共端口。当子进程投入使用时,使用 NodeJS 的系统可以处理更大的工作量。
(3) 后端的 Node.js
互联网已经成为全球数以百万计公司的首选平台。因此,为使一家企业发挥最大潜力,并在此过程中脱颖而出,必须拥有强大的网络形象。
这一切都始于一个强大而直观的网站。要打造一个完美无瑕的网站,重要的是选择最佳的前端和后端技术。尽管本质上是单线程的,但 Node.js 是开发后端 Web 服务的首选。
尽管有大量的后端多线程选择,但知名公司还是喜欢 Node.js。这是因为 Node.js 提供了在 JavaScript 中使用多线程的变通方法,而 JavaScript 已经是“Web上最流行的编程语言”。
总结
worker_threads 模块提供了一种在 Node.js 程序中实现多线程的简便方法。通过将繁重的计算委派给工作线程,可以显着提高服务器的吞吐量。
借助对多线程的支持,Node.js 将继续吸引越来越多的来自 AI、大数据和机器学习等计算密集型领域的开发人员、工程师和其他专业人员。
相关推荐
- Nat. Synthesis: 重大突破,电化学形成C-S键
-
第一作者:JunnanLi,HasanAl-Mahayni通讯作者:AliSeifitokaldani,NikolayKornienko通讯单位:蒙特利尔大学,麦吉尔大学【研究亮点】形成C-...
- 网络安全与应用(二)(网络安全理论与应用)
-
1、应用层安全协议SHTTP和HTTPS:SHTTP:SecHTTP,安全超文本传输协议,是HTTP扩展,使用TCP的80端口。HTTPS:HTTP+SSL,使用TCP的443端口。大部分web应用...
- TN-C、TN-S、TT、IT供电系统详解及对比
-
TN-C、TN-S、TT、IT供电系统是低压配电系统中常见的四种接地方式,它们各自有不同的特点和适用场景。一、系统介绍TN-C供电系统①定义:整个系统中,工作零线(N线)与保护零线(PE线)是合一的,...
- 网络应用服务器(三)(网络应用程序服务器)
-
#头条创作挑战赛#1、DNS协议:域名解析协议,用于把主机域名解析为对应的IP地址。是一个分布式数据库,C/S工作方式。主要基于UDP协议,少数使用TCP,端口号都是53。常用域名如下2、DNS协议...
- 腾讯发布混元Turbo S:业界首次无损应用Mamba架构
-
21世纪经济报道记者白杨北京报道2月27日,腾讯正式发布新一代基座模型——混元TurboS。据腾讯混元团队介绍,混元TurboS在架构方面创新性地采用了Hybrid-Mamba-Transfor...
- 【收藏】低压配电系统中TT IT TN-S/TN-C/TN-C-S 的区别?
-
低压配电系统的接地型式选择是电气安全设计的核心环节,TT、IT、TN-S、TN-C、TN-C-S这五种主要接地型式因其结构、保护原理和故障特性的显著差异,在工程应用中有不同的适用范围和限制条件。如若发...
- 金万维公有云平台如何实现C/S架构软件快速SaaS化
-
金万维作为国内领先的企业信息化垂直B2B平台运营商,拥有超过5000家管理软件合作伙伴,掌握管理软件一线的发展动态,因此深知传统管理软件近年来面对的困境和问题。而SaaS却在软件行业内发展迅猛势如燎原...
- 随时随地做翻译:B/S架构的传奇时代到来
-
随着新兴技术的发展和大数据时代的到来,翻译作为连接各国语言和文化的工具,更是具有前所未有的拓展空间。传统的在计算机辅助翻译软件(CAT)上进行翻译的模式,受到时间和空间的限制,导致翻译过程中面临层层障...
- BS和CS 架构的介绍(一篇就够了)(cs和bs架构的含义)
-
简介C/S又称Client/Server或客户/服务器模式。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如Oracle、Sybase、Informix或SQLServer。...
- 物管王(包租婆)软件架构与B/S和C/S架构的优点和缺点比较
-
一、B/S系统架构的优点和缺点优点:1)客户端无需安装,有Web浏览器即可。2)BS架构可以直接放在广域网上,通过一定的权限控制实现多客户访问的目的,交互性较强。3)BS架构无需升级多个客户端,升级服...
- 监听器入门看这篇就够了(怎么检查车上有没有被别人安装监听器)
-
什么是监听器监听器就是一个实现特定接口的普通java程序,这个程序专门用于监听另一个java对象的方法调用或属性改变,当被监听对象发生上述事件后,监听器某个方法将立即被执行。。为什么我们要使用监听器?...
- 购物车【JavaWeb项目、简单版】(java购物车的实现原理)
-
①构建开发环境免费学习资料获取方式导入需要用到的开发包建立程序开发包②设计实体书籍实体publicclassBook{privateStringid;privat...
- 基础篇-SpringBoot监听器Listener的使用
-
1.监听器Listener简介1.1监听器Listener介绍Listener是JavaWeb的三大组件(Servlet、Filter、Listener)之一,JavaWeb中的监听器主要用...
- 你在 Spring Boot3 整合 JWT 实现 RESTful 接口鉴权时是否遇到难题?
-
各位后端开发小伙伴们!在日常使用SpringBoot3搭建项目时,RESTful接口的鉴权至关重要。而JWT技术,作为一种简洁且高效的鉴权方式,被广泛应用。但大家是不是在整合过程中遇到过各...
- javaWeb RSA加密使用(rsa加密java代码)
-
加密算法在各个网站运用很平常,今天整理代码的时候看到了我们项目中运用了RSA加密,就了解了一下。先简单说一下RSA加密算法原理,RSA算法基于一个十分简单的数论事实:将两个大质数相乘十分容易,但是想要...
你 发表评论:
欢迎- 一周热门
- 最近发表
- 标签列表
-
- maven镜像 (69)
- undefined reference to (60)
- zip格式 (63)
- oracle over (62)
- date_format函数用法 (67)
- 在线代理服务器 (60)
- shell 字符串比较 (74)
- x509证书 (61)
- localhost (65)
- java.awt.headless (66)
- syn_sent (64)
- settings.xml (59)
- 弹出窗口 (56)
- applicationcontextaware (72)
- my.cnf (73)
- httpsession (62)
- pkcs7 (62)
- session cookie (63)
- java 生成uuid (58)
- could not initialize class (58)
- beanpropertyrowmapper (58)
- word空格下划线不显示 (73)
- jar文件 (60)
- jsp内置对象 (58)
- makefile编写规则 (58)