【问题标题】:How does Node.js process incoming requests?Node.js 如何处理传入的请求?
【发布时间】:2020-09-16 15:26:15
【问题描述】:

为了深入了解有关 Node.js 的更复杂概念,我正在做一些研究,以确保我了解有关该语言的原则及其构建的基本构建块。

就我而言,Node.js 依赖 反应器模式 来处理每个传入的请求。该算法基于 Event Demultiplexer 算法。第二个负责处理请求操作及其资源,然后,一旦操作完成,它将“结果”添加到事件队列。在此过程之后,Event Loop 现在负责执行每个事件的处理程序。

作为一个单线程进程,如果事件循环并行管理所有事件队列任务,我很难理解事件多路分解器如何处理所有传入操作...

我在Node.js documentation 中找到了这个:

由于大多数现代内核都是多线程的,它们可以处理多个 在后台执行的操作。当这些操作之一 完成后,内核告诉 Node.js 以便适当的回调 可能会被添加到轮询队列中以最终被执行。好吧 稍后在本主题中进一步详细解释这一点。

这是否意味着 Node 不处理 Event Demultiplexer 任务并且 Node 只是获取结果以便将其添加到事件队列中?这不是说 Node 不是单线程的吗?

我在网上找到了一些有用的图表,它们清楚地解释了每个请求所遵循的路径,但是真的很难找到一些解释线程处理每个请求的实际时间的图表。

【问题讨论】:

  • 通常,每个执行上下文有一个事件循环。为了利用多个 CPU 内核,cluster 模块用于分叉额外的处理循环。此外,节点在用户代码中是单线程的。每当你调用一个库函数时,它的内部可以做任何事情,甚至产生线程,只要将结果放回由你的用户代码单线程处理的事件循环中。
  • 我发现这个谈话真的很有帮助,以防有人感兴趣youtu.be/zphcsoSJMvM

标签: javascript node.js event-loop libuv principles


【解决方案1】:

在 node.js 中,它在单个线程中运行您的 Javascript(假设我们不是在谈论工作线程或集群)。但是,node.js 内置库中的许多异步操作(例如文件 I/O 或一些加密操作)使用它们自己的线程来完成它们的任务。因此,当您调用诸如fs.open() 之类的异步操作来打开文件时,它会转换为本机代码,从内部线程池中获取一个线程,然后该线程开始打开文件。 fs.open() 函数然后返回到您的 Javascript(而线程在后台继续运行)。稍后,当它完成任务时,内部线程将一个事件插入到 nodejs 事件队列中,当 nodejs 有循环检查事件队列时,它会找到该事件并运行与之关联的 Javascript 回调以将异步结果返回给你的 Javascript。

因此,即使可能涉及线程,您的 Javascript 仍然是通过事件循环的单线程。

所以,nodejs 确实使用原生代码线程来进行一些内部原生代码操作。网络和计时器等其他东西是在没有线程的情况下实现的。

那么如果我在 Node 中发送一个从数据库中获取数据的请求,Event Demultiplexer 是如何处理它的呢?主线程是否停止事件循环以处理该操作,然后在事件处理程序排队后恢复?

像“Event Demultiplexor”这样的术语是你应用于 node.js 的东西。它们根本不是 node.js 使用的东西,所以我不完全确定你在问什么。

Node.js 一次运行一个事件。它没有中断驱动的能力。因此,它会运行一个事件,直到该事件将控制权返回给事件循环(通过从启动一切的回调中发出return)。现在,原始事件可能不完整 - 它可能正在执行一些异步操作,触发另一个事件来宣布完成,但它现在已经完成了 Javascript 的运行并将控制权返回给事件循环。

当传入的 Fetch 请求(只是传入的 http 请求)到达服务器时,它首先由操作系统排队。然后,当事件循环有机会看到它时,它会被添加到 node.js 事件队列中,并在它之前的其他事件完成处理时以 FIFO 顺序提供服务。现在,nodejs 事件循环并不像单个事件队列那么简单。它实际上有几个不同的队列用于不同类型的工作,并为首先运行的内容设置了优先级,但在最简单的级别上,您可以开始将其视为单个 FIFO 队列。而且,什么都不会被打断。

从事件队列中拉出一个事件,运行与之关联的 Javascript 回调。当该回调返回事件循环时,获取下一个事件并执行相同操作。

事件可以通过本机代码线程(例如可能通过文件 I/O 或某些加密操作完成)或通过作为它检查的事件循环周期的一部分内置在事件循环中的某些轮询机制添加到事件队列中对于某些准备好运行的东西(如网络和计时器)。

【讨论】:

  • 那么如果我在Node中发送一个从数据库中获取数据的请求,Event Demultiplexer是如何处理的呢?主线程是否停止事件循环以处理该操作,然后在事件处理程序排队后恢复?
  • @LuisOrbaiceta - 查看我在答案中添加的内容。如果您使用 nodejs 用来描述自己的术语而不是您自己的术语会更好,因为我们其他人并不真正知道您自己的术语(例如“事件分离器”)在这种情况下的含义,因为那不是nodejs 术语。
  • 我在 Mario Casciaro 在他的“Node.Js 设计模式”一书中给出的反应器模式解释中读到了这个术语 miro.medium.com/max/1582/1*MABVZQvtz5jkv4Fh23kzRg.png
  • @LuisOrbaiceta - 嗯,我从未听说过在 node.js 中称为事件多路复用器的东西,所以这显然是那篇文章的作者应用的一个术语。我不确定那篇文章是从哪里得到的。有多个事件队列(用于不同类型的事件)和一个事件循环,该循环以特定顺序循环通过不同队列,并具有特定优先级来决定队列中接下来要处理的待处理事件。
  • 但就我而言,Node 最重要的构建块是 Libuv,它基于反应器模式构建,具有同步事件解复用器来处理所有非阻塞系统 I/O
猜你喜欢
  • 1970-01-01
  • 2013-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-26
  • 1970-01-01
  • 1970-01-01
  • 2012-03-21
相关资源
最近更新 更多