做者:Nastassia Ovchinnikova翻译:疯狂的技术宅javascript
原文:https://flatlogic.com/blog/mu...前端
未经容许严禁转载java
Node.js 是一个免费的跨平台 JavaScript 运行时环境,尽管它本质上是单线程的,可是能够在后台使用多个线程来执行异步代码。node
因为 Node.js 的非阻塞性质,不一样的线程执行不一样的回调,这些回调首先委托给事件循环。 Node.js 运行时负责处理全部这一切。程序员
JavaScript 最初是做为一种单线程编程语言构建的,仅在 Web 浏览器中运行。这意味着在一个过程当中,只有一组指令可以在给定的时间执行。web
仅在当前代码块的执行完成后,才移至下一个代码块。可是,JavaScript 的单线程性质使实现变得容易。面试
最初,JavaScript 对于仅用于向网站添加少许交互。因此并无对多线程的需求。可是时代已经变了,用户要求也愈来愈高,JavaScript 已成为“Web 上流行的编程语言”。编程
多线程如今变得很广泛。因为 JavaScript 是单线程语言,所以没法在其中实现多线程。幸运的是,在这种状况下,有一个很好的解决方法:Node.js。segmentfault
Node.js 框架并很多,这要归功于 JavaScript 运行时环境(尤为是 JavaScript)的广泛流行。在继续本文以前,让咱们了解一些有关 Node.js 的重要观点:后端
在两种状况下,咱们须要 fork 一个流程:
能够将数据发送到子进程,也能够将其送回。
Node.js 使用两种类型的线程:
事件循环负责获取回调或函数,并将其注册以供未来执行。它与正确的 JavaScript 代码在同一线程中运行。一旦 JavaScript 操做阻塞了线程,事件循环也会被阻塞。
工做池是一个执行模型,负责产生和处理不一样的线程。它同步执行任务,而后将结果返回到事件循环,最后事件循环将结果提供给回调。
总而言之,工做池负责异步 I/O 操做,即与系统磁盘和网络的交互。像 fs 和 crypto 这样的模块是使用工做池的主要模块。
因为工做池是在 libuv 库中实现的,Node.js 在 JS 和 C++ 之间进行内部通讯时会稍有延迟。不过这几乎是不可察觉的。
一切都很好,直到咱们遇到同步执行复杂操做的要求。任何须要大量时间执行的函数都会致使主线程阻塞。
若是程序具备多个占用大量 CPU 的函数,将会致使服务器吞吐量的显着降低。在最坏的状况下,服务器将会失去响应,而且没法将任务委派给工做池。
诸如 AI、大数据和机器学习之类的领域没法从 Node.js 中受益,由于这些操做阻塞了主线程,并使服务器失去响应。可是这随着 Node.js v10.5.0 的到来而改变,该版本增长了对多线程的支持。
在 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 模块。
Node.js v10.5.0 于 2018 年 6 月发布,引入了 worker_threads 模块。它有助于在流行的 JavaScript 运行时环境中实现并发。该模块容许建立功能齐全的多线程 Node.js 应用。
从技术上讲,工做线程是在单独的线程中产生的一些代码。要开始使用辅助线程,须要先导入 worker_threads 模块。以后须要建立 Worker 类的实例以建立工做线程。
建立 Worker 类的实例时,有两个参数:
辅助线程可以调度多个消息事件。所以,回调方法优先于返回 promise。
工做线程之间的通讯是基于事件的,即侦听器设置为在工做线程发送事件后当即调用。最多见的 4 个事件是:
worker.on('error', (error) => {});
worker.on('exit', (exitCode) => {})
process.exit()
,则会将 exitCode 提供给回调。若是 worker.terminate()
终止工做线程,则代码为 1。worker.on('message', (data) => {});
worker.on('online', () => {});
有两种使用工做线程的方法:
方法 2 也被称为工做池。这是由于该方法涉及建立 worker 的工做池,先让他们等待,并在须要时去调度消息事件来执行任务。
因为从头建立工做线程须要建立虚拟机以及解析和执行代码,所以官方 Node.js 文档 建议采用方法 2。此外,方法 2 更为实用,比方法 1 更有效。
为了使 Node.js 利用多核系统的功能,能够用一些进程。流行的 javascript 运行时环境中有称被为 cluster 的模块,该模块提供对多进程的支持。
使用 cluster 模块能够产生多个子进程,这些子进程能够共享一个公共端口。当子进程投入使用时,使用 NodeJS 的系统能够处理更大的工做量。
互联网已经成为全球数以百万计公司的首选平台。所以,为使一家企业发挥最大潜力,并在此过程当中脱颖而出,必须拥有强大的网络形象。
这一切都始于一个强大而直观的网站。要打造一个完美无瑕的网站,重要的是选择最佳的前端和后端技术。尽管本质上是单线程的,但 Node.js 是开发后端 Web 服务的首选。
尽管有大量的后端多线程选择,但知名公司仍是喜欢 Node.js。这是由于 Node.js 提供了在 JavaScript 中使用多线程的变通方法,而 JavaScript 已是“Web上最流行的编程语言”。
worker_threads 模块提供了一种在 Node.js 程序中实现多线程的简便方法。经过将繁重的计算委派给工做线程,能够显着提升服务器的吞吐量。
借助对多线程的支持,Node.js 将继续吸引愈来愈多的来自 AI、大数据和机器学习等计算密集型领域的开发人员、工程师和其余专业人员。