探索Node.js:其异步魔术背后的核心概念
#node #eventloop #nodeasync

最近,Node.js已成为开发人员中最受欢迎的语言。它的声誉在很大程度上归功于其异步性质和非阻塞IO能力。在过去的四年中,亲自使用了Node.js,我可以证明其出色的速度和可扩展性。但是,许多人无法掌握的是Node.js在内部处理这些IO操作和CPU密集型任务的方式。

在这篇博客文章中,我们将深入研究Node.js使用的模式来处理传入请求,并探讨为什么它胜过其他语言。我们将介绍此旅程中的以下主题:

  1. 阻止I/O
  2. 非阻滞I/O
  3. 退路事件
  4. node.js核心模式

阻止I/O:
传统上,在编程语言中,当进行与IO操作相对应的呼叫时,它会阻止线程的执行,直到数据可用为止。因此,线程保持空闲状态,等待数据,在此期间没有其他目的。可以在下图(Image1)中可视化此情况。

Image description

当我们考虑各种IO操作(例如与数据库或文件系统交互)可能会阻止请求时,问题就变得显而易见。结果,线程可能经常阻止等待IO操作的结果,从而导致内存消耗增加,上下文切换开销和过度使用CPU。这样的空闲时间不利于线程的效率。

非阻滞IO:
非阻滞IO的概念涉及在执行IO操作时不等待任何数据或响应。如果没有立即响应,则系统调用必须立即返回到发动机。这样,该线程不会被阻止以进行响应,从而可以处理其他请求。因此,与阻断IO相比,线程的空闲时间大大减少,如Image2所示。

Image description

事件消除:
事件消除是一种高级技术。在电信中,多路复用是将多个信号组合到一个信号中以促进有限容量介质的传输的过程。另一方面,消失将组合信号分配回其原始组件。类似的概念适用于各个领域,包括视频处理。

在node.js中,同步的事件撤消者同时观看多个资源。当完成任何资源上的任何操作时,它将返回新事件。请注意,它返回一个新活动。同步事件反复链路块,直到可以处理新事件为止。以下是同步事件退路器的伪代表。

watchedList.add(socketA, FOR_READ) // (1)
watchedList.add(fileB, FOR_READ)
while (events = demultiplexer.watch(watchedList)) { // (2)
// event loop
for (event of events) { // (3)
// This read will never block and will always return data
data = event.resource.read()
if (data === RESOURCE_CLOSED) {
// the resource was closed, remove it from the watched list
demultiplexer.unwatch(event.resource)
} else {
// some actual data was received, process it
consumeData(data)
}
}
}

该过程的工作原理如下:

资源(IO事件)被添加到与操作关联的数据结构中。
弹路器设置为观看这些事件,每个呼叫都是同步的,阻塞直到准备了指定操作的资源(例如,读取)。
操作完成后,EmultiPlexer会创建一个新事件,该事件将进一步处理或执行。
事件撤消者返回的每个事件都会处理。此时,相关资源可以保证可以在操作过程中读取而不是阻止。处理所有事件后,事件撤消器上的流量块再次将进行处理,直到可以处理新事件为止。这个周期称为事件循环。
下图演示了服务器如何利用同步事件删除器和单个线程来处理多个并发连接。

node.js核心模式:
Node.js使用的核心模式称为反应器模式。它围绕着将处理程序与每个IO操作相关联,该操作程序由Node.js中的回调表示。以下是反应器模式的表示:

Image description

以下步骤使用反应器模式阐明了应用程序的行为:

该应用程序通过向事件删除媒体提交请求来生成新的IO操作。同时,应用程序指定处理程序,该处理程序将在操作完成时调用。此提交是一个非阻止调用,并且立即将控件返回到应用程序。
当一组IO操作完成时,事件解答器将相应的事件推入事件队列。
事件循环在事件队列中的项目上迭代。
对于每个事件,都调用关联的处理程序。
处理程序是应用程序代码的一部分,一旦执行完成后,将控制权放回事件循环(5A)。在执行期间,处理程序可以要求新的异步操作(5B),导致新项目添加到事件弹出器(1)中。
事件队列中的所有项目都被处理后,事件弹出器上的事件循环块将在有新事件可用时触发另一个周期。
异步行为清楚地出现。该应用程序表示对访问资源而无需阻止的兴趣,并且提供了一个处理程序,该处理程序将在操作完成后调用。

node.js利用这种异步模式,有助于其出色的速度和效率。

结论:
Node.js通过利用其异步性和非阻滞IO功能来实现无与伦比的速度和可扩展性,理所当然地赢得了其知名度。事件反复运输和反应堆模式的组合形成了node.js的核心,使其能够以显着的效率处理多个并发请求。

希望您能找到这篇文章启发。请考虑分享并通过拍手表示感谢!

Resource-Node.js设计模式 - 第三版Mario Casciaro,Luciano Mammo