一文搞懂 Node.js 中的多线程和多进程

做者:Nastassia Ovchinnikova

翻译:疯狂的技术宅javascript

原文:https://flatlogic.com/blog/mu...前端

未经容许严禁转载java

Node.js 是一个免费的跨平台 JavaScript 运行时环境,尽管它本质上是单线程的,可是能够在后台使用多个线程来执行异步代码。node

因为 Node.js 的非阻塞性质,不一样的线程执行不一样的回调,这些回调首先委托给事件循环。 Node.js 运行时负责处理全部这一切。程序员

为何要使用NodeJS?

JavaScript 最初是做为一种单线程编程语言构建的,仅在 Web 浏览器中运行。这意味着在一个过程当中,只有一组指令可以在给定的时间执行。web

仅在当前代码块的执行完成后,才移至下一个代码块。可是,JavaScript 的单线程性质使实现变得容易。面试

最初,JavaScript 对于仅用于向网站添加少许交互。因此并无对多线程的需求。可是时代已经变了,用户要求也愈来愈高,JavaScript 已成为“Web 上流行的编程语言”。编程

多线程如今变得很广泛。因为 JavaScript 是单线程语言,所以没法在其中实现多线程。幸运的是,在这种状况下,有一个很好的解决方法:Node.js。segmentfault

Node.js 框架并很多,这要归功于 JavaScript 运行时环境(尤为是 JavaScript)的广泛流行。在继续本文以前,让咱们了解一些有关 Node.js 的重要观点:后端

  1. 能够用 send 函数将消息从子进程传递到其余子进程和主进程
  2. 支持 fork 多个进程
  3. 主进程和子进程之间不共享状态

为何要 fork 进程?

在两种状况下,咱们须要 fork 一个流程:

  1. 经过将任务委派给其余进程来提升速度
  2. 用于释放内存和卸载单个进程

能够将数据发送到子进程,也能够将其送回。

Node.js 的方式

Node.js 使用两种类型的线程:

  1. 经过事件循环处理主线程,
  2. 工做池中有许多辅助线程

事件循环负责获取回调或函数,并将其注册以供未来执行。它与正确的 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 类的实例时,有两个参数:

  1. 第一个参数提供扩展名 .js 或 .mjs 的文件路径,其中包含工做程序线程的代码,
  2. 第二个参数提供了一个包含 workerData 属性的对象,该属性包含工做线程开始执行时将访问的数据

辅助线程可以调度多个消息事件。所以,回调方法优先于返回 promise。

工做线程之间的通讯是基于事件的,即侦听器设置为在工做线程发送事件后当即调用。最多见的 4 个事件是:

worker.on('error', (error) => {});
  1. 当工做线程中有未捕获的异常时发出。接下来工做线程终止,而且该错误能够做为回调中的第一个参数使用。
worker.on('exit', (exitCode) => {})
  1. 当辅助线程退出时发出。若是在工做线程中调用了 process.exit(),则会将 exitCode 提供给回调。若是 worker.terminate() 终止工做线程,则代码为 1。
worker.on('message', (data) => {});
  1. 当工做线程将数据发送到父线程时发出。
worker.on('online', () => {});
  1. 当工做线程中止解析 JS 代码并开始执行时发出。尽管不经常使用,但 online 事件在特定状况下可能会提供更多信息。

使用工做线程的方式

有两种使用工做线程的方法:

  • 方法 1 – 涉及产生工做线程,执行其代码并将结果发送到父线程。此方法须要每次为新任务从头建立新的 worker 线程。
  • 方法 2 – 涉及生成 worker 线程并为消息事件设置侦听器。每次触发该消息时,辅助线程都会执行代码,并将结果发送回父线程。辅助线程保持活动状态,以备未来使用。

方法 2 也被称为工做池。这是由于该方法涉及建立 worker 的工做池,先让他们等待,并在须要时去调度消息事件来执行任务。

因为从头建立工做线程须要建立虚拟机以及解析和执行代码,所以官方 Node.js 文档 建议采用方法 2。此外,方法 2 更为实用,比方法 1 更有效。

worker_threads 模块中可用的重要属性

  • isMainThread – 当不在工做线程内操做时,此属性为 true。若是须要,则能够在 worker 文件的开头包含一个简单的 if 语句。这样能够确保它仅做为工做线程运行。
  • parentPort – MessagePort 的实例,用于与父线程进行通讯。
  • threadId – 分配给工做线程的惟一标识符。
  • workerData – 包含在 worker 线程的构造函数中的数据。

Node.js 中的多进程

为了使 Node.js 利用多核系统的功能,能够用一些进程。流行的 javascript 运行时环境中有称被为 cluster 的模块,该模块提供对多进程的支持。

使用 cluster 模块能够产生多个子进程,这些子进程能够共享一个公共端口。当子进程投入使用时,使用 NodeJS 的系统能够处理更大的工做量。

后端的 Node.js

互联网已经成为全球数以百万计公司的首选平台。所以,为使一家企业发挥最大潜力,并在此过程当中脱颖而出,必须拥有强大的网络形象。

这一切都始于一个强大而直观的网站。要打造一个完美无瑕的网站,重要的是选择最佳的前端和后端技术。尽管本质上是单线程的,但 Node.js 是开发后端 Web 服务的首选。

尽管有大量的后端多线程选择,但知名公司仍是喜欢 Node.js。这是由于 Node.js 提供了在 JavaScript 中使用多线程的变通方法,而 JavaScript 已是“Web上最流行的编程语言”。

总结

worker_threads 模块提供了一种在 Node.js 程序中实现多线程的简便方法。经过将繁重的计算委派给工做线程,能够显着提升服务器的吞吐量。

借助对多线程的支持,Node.js 将继续吸引愈来愈多的来自 AI、大数据和机器学习等计算密集型领域的开发人员、工程师和其余专业人员。


本文首发微信公众号:前端先锋

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎扫描二维码关注公众号,天天都给你推送新鲜的前端技术文章

欢迎继续阅读本专栏其它高赞文章:


相关文章
相关标签/搜索