【问题标题】:Event loop in Node.jsNode.js 中的事件循环
【发布时间】:2020-02-07 05:22:03
【问题描述】:

我们都知道,在 Node.js 中,函数由工作线程处理执行,然后发送到事件队列,然后事件循环查看调用堆栈。 如果调用堆栈为空,则事件循环将函数的上下文环境调用堆栈,然后调用堆栈对其进行处理并将其作为响应。

我的问题是,如果我们有多个具有相同超时函数的函数,然后所有函数都交给工作线程,那么工作线程将它们的上下文环境发送到事件队列, 如果所有函数的超时时间相同,则它们都同时进入事件队列,如果调用堆栈为空,则事件循环将所有函数发送到调用堆栈,我们都知道的属性堆栈是 FILO。

所以如果发生这种情况导致最后一个函数应该首先发送响应,但如果所有超时都相同,第一个函数会首先响应?

【问题讨论】:

  • 您的问题中有很多误解。 Node.js 是单线程的。所有函数都在同一个线程上运行。事件循环是 Node.js 如何使用一个线程来管理在不同时间调用多个函数的方式。 唯一 node.js 使用多个线程的事情是磁盘 I/O(网络 I/O 是单线程的)、DNS(因为 DNS 是阻塞的)和一些加密功能(因为加密使用 CPU 并且是不是真正的 I/O)
  • @DeepKakkar - 除了这个问题中的很多陈述都是错误的。这不是它的工作原理。
  • 有关 node.js 工作原理的高级描述,请参阅:stackoverflow.com/questions/34855352/…
  • 另外,你想达到什么目的或者这是一个哲学问题?

标签: node.js


【解决方案1】:

您在问题中描述事物的方式有很多错误,但我会谈谈您询问的超时问题。

nodejs 有自己的计时器系统。它保留了一个排序的计时器列表,并且唯一具有物理系统计时器的 Javascript 超时是下一个要触发的。如果多个 Javascript 超时设置为在同一时间点触发,则它们都共享同一个操作系统计时器。

当该 OS 计时器触发并且主 JS 线程空闲并且能够从事件循环中提取下一个事件时,它将看到一个 JS 计时器已准备好调用其回调。如果有不止一个准备就绪,而且都在同一时间,那么解释器将按照定时器的配置顺序(FIFO)一个接一个地调用它们的每个回调。

我们都知道,在 Node.js 中,函数由工作线程处理执行,然后发送到事件队列,然后事件循环查看调用堆栈。如果调用堆栈为空,则事件循环将函数的上下文环境调用堆栈,然后调用堆栈对其进行处理并将其作为响应。

我的问题是,如果我们有多个具有相同超时函数的函数,然后所有函数都交给工作线程

那部分是错误的。它们不会被分配给工作线程。

然后工作线程将其上下文环境发送到事件队列,如果所有函数的超时时间相同,则它们都同时进入事件队列

如上所述,定时器是事件循环代码中的一种特殊类型的事件。他们一次只使用一个系统计时器来安排下一个计时器触发。设置为同时触发的多个计时器都存储在同一个列表(该特定时间的列表元素)中,并且在轮到他们下一个时都共享相同的操作系统计时器。因此,它们不会同时进入事件队列。 Nodejs 为同时触发的一组定时器设置了一个系统定时器。当该系统计时器触发并且解释器可以从事件循环中提取下一个事件时,它将按照 FIFO 顺序依次调用为该时间设置的每个计时器的每个回调。

然后如果调用栈为空则事件循环会将所有函数发送到调用栈,我们都知道栈的属性是FILO。

我不知道“将所有函数发送到该调用堆栈”是什么意思。事情根本不是这样运作的。 node.js 在单个线程中运行您的 Javascript(除了 WorkerThreads 不在此处运行),因此它为一个计时器调用回调,将其运行到完成,然后为下一个计时器调用回调,将其运行到完成等等上...

所以如果发生这种情况导致最后一个函数应该首先发送响应,但如果所有超时都相同,第一个函数会首先响应?

正如我在上面多次说过的,多个设置为同时触发的计时器使用一个系统计时器,当该系统计时器触发时,每个计时器的回调按 FIFO 顺序依次调用。


参考文献

您可以在此处了解有关 node.js 计时器架构的更多信息:How does Node.js manage timers

还有,这里有一些关于 node.js 计时器架构的更多信息,取自源代码中的 cmets:How many concurrent setTimeouts before performance issues?

Looking for a solution between setting lots of timers or using a scheduled task queue

Six Part Series on the Node.js Event Loop and How It Works

【讨论】:

  • 添加了几个关于计时器和事件循环的引用。
【解决方案2】:

我的问题是我们是否有多个具有相同超时的函数 功能

轮询阶段控制定时器

First read here

I highly recommend this series

所以主要的问题是 Node 如何决定接下来要运行什么代码?

正如我们所知,Event Loop 和 Worker Pool 分别维护待处理事件和待处理任务的队列。

不要和Worker线程混淆


工作线程是不同的概念Read here

但实际上,事件循环实际上并不维护队列。相反,它有一个 file descriptors 的集合,它要求操作系统使用 epoll (Linux)、kqueue (OSX)、事件端口 (Solaris) 或 IOCP (Windows) 等机制进行监控。这些文件描述符对应于网络套接字、它正在监视的任何文件等等。当操作系统说这些文件描述符之一准备就绪时,事件循环将其转换为适当的事件并调用与该事件关联的回调

工作池使用一个真正的队列,其条目是要处理的任务。一个 Worker 从这个队列中弹出一个任务并处理它,当完成时,Worker 会为 Event Loop 引发一个“至少一个任务完成”事件。

定时器回调的调用取决于系统的性能(节点在执行回调之前必须检查一次定时器是否过期,这需要一些 CPU 时间)以及事件循环中当前正在运行的进程。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    • 2015-10-13
    • 2015-07-14
    • 2018-01-15
    • 1970-01-01
    • 1970-01-01
    • 2019-02-20
    相关资源
    最近更新 更多