当前位置: 首页 > 知识库问答 >
问题:

Nodejs事件循环

松灿
2023-03-14

nodejs架构中是否有两个内部事件循环?

  • libev/libuv
  • v8 javascript事件循环

在I/O请求时,node是否将请求排队发送到libeio,然后lib eio使用libev通过事件通知数据的可用性,最后这些事件由v8事件循环使用回调处理?

基本上,libev和libeio在nodejs架构中是如何集成的?

是否有任何留档可以提供nodejs内部架构的清晰图片?

共有3个答案

颛孙越
2023-03-14

libuv简介

node.js项目始于2009年,是一个与浏览器分离的JavaScript环境。使用Google的V8和Marc Lehmann的libev,node.js将I/O模型——evented——与非常适合编程风格的语言结合起来;因为它是由浏览器塑造的。随着node.js越来越受欢迎,让它在Windows上工作变得很重要,但是libev只能在Unix上运行。与内核事件通知机制(如kqueue或(e)poll)相当的Windows是IOCP。libuv是基于平台的libev或IOCP的抽象,为用户提供基于libev的API。在node-v0.9.0版本的libuv中删除了libev。

还有一张描述Node.js中事件循环的图片

更新05/09/2017

根据这个文档Node.js事件循环,

下图简要概述了事件循环的操作顺序。

   ┌───────────────────────┐
┌─>│        timers         │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     I/O callbacks     │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
│  │     idle, prepare     │
│  └──────────┬────────────┘      ┌───────────────┐
│  ┌──────────┴────────────┐      │   incoming:   │
│  │         poll          │<─────┤  connections, │
│  └──────────┬────────────┘      │   data, etc.  │
│  ┌──────────┴────────────┐      └───────────────┘
│  │        check          │
│  └──────────┬────────────┘
│  ┌──────────┴────────────┐
└──┤    close callbacks    │
   └───────────────────────┘

注意:每个方框将被称为事件循环的一个“阶段”。

阶段概述

  • 定时器:此阶段执行由setTimeout()setInterval()调度的回调。
  • I/O回调:执行几乎所有回调,除了关闭回调、计时器调度的回调和setIm的()
  • 空闲,准备:仅内部使用。
  • 投票:检索新的I/O事件;节点将在适当的时候阻塞这里。
  • 检查:setIm
  • 关闭回调:例如socket.on('关闭',…)

在事件循环的每次运行之间,Node.js检查它是否在等待任何异步I/O或计时器,如果没有,就彻底关闭。

方季同
2023-03-14

看起来讨论的一些实体(例如:libev等)已经失去了相关性,因为这已经有一段时间了,但我认为这个问题仍然有很大的潜力。

让我借助一个抽象的例子,在一个抽象的UNIX环境中,在节点的上下文中,解释一下事件驱动模型的工作原理。

计划的视角:

  • 脚本引擎开始执行脚本。
  • 任何时候遇到CPU绑定操作时,它都会以其完整性内联(实机)执行。
  • 每当遇到I/O绑定操作时,请求及其完成处理程序都会注册到“事件机制”(虚拟机)
  • 以同样的方式重复上述操作,直到脚本结束。CPU绑定操作-执行内联、I/O绑定操作,如上向机器请求。
  • 当I/O完成时,将回调侦听器。

上面的事件机制称为libuv-AKA事件循环框架。Node利用此库实现其事件驱动编程模型。

节点的视角:

  • 有一个线程来托管运行时。
  • 拿起用户脚本。
  • 将其编译为本机 [ 利用 v8 ]
  • 加载二进制文件,然后跳转到入口点。
  • 编译的代码使用编程基元以内联方式执行 CPU 绑定活动。
  • 许多与 I/O 和计时器相关的代码都有本机包装。例如,网络 I/O。
  • 因此,I/O 调用从脚本路由到 C 桥,I/O 句柄和完成处理程序作为参数传递。
  • 本机代码执行 libuv 循环。它获取循环,将表示 I/O 的低级事件和本机回调包装器排队到 libuv 循环结构中。
  • 本机代码返回到脚本 - 当前没有发生 I/O!
  • 上述项重复多次,直到所有非 I/O 代码都执行完毕,并且所有 I/O 代码都注册到 libuv 中。
  • 最后,当系统中没有任何东西可以执行时,节点将控制权传递给libuv
  • libuv 开始行动,它拾取所有注册的事件,查询操作系统以获取它们的可操作性。
  • 那些在非阻塞模式下准备好进行 I/O 的,将被拾取,执行 I/O,并发出它们的回调。一个接一个。
  • 那些尚未准备好的(例如套接字读取,另一个endpoint尚未写入任何内容)将继续与操作系统一起探测,直到它们可用。
  • 循环在内部保持不断增加的计时器。当html" target="_blank">应用程序请求延迟回调(例如 setTimeout)时,将利用此内部计时器值来计算触发回调的正确时间。

虽然大多数功能都以这种方式得到满足,但文件操作的某些(异步版本)是在附加线程的帮助下执行的,这些线程很好地集成到 libuv 中。虽然网络 I/O 操作可以等待外部事件,例如其他endpoint响应数据等,但文件操作需要节点本身的一些工作。例如,如果您打开一个文件并等待 fd 准备好数据,它不会发生,因为实际上没有人在阅读!同时,如果您从主线程中的内联文件读取,它可能会阻止程序中的其他活动,并可能出现明显问题,因为与 CPU 绑定活动相比,文件操作非常慢。因此,从程序的角度来看,内部工作线程(UV_THREADPOOL_SIZE可通过环境变量配置)用于对文件进行操作,而事件驱动的抽象则完好无损地工作。

希望这有所帮助。

鲁建茗
2023-03-14

我一直在亲自阅读node.js的源代码

当我试图理解node.js架构以编写本机模块时,我遇到了类似的问题。

我在这里发布的是我对node.js的理解,这也可能有点偏离轨道。

>

  • Libev是实际上在节点内部运行的事件循环。js来执行简单的事件循环操作。它最初是为*nix系统编写的。Libev为流程提供了一个简单而优化的事件循环。您可以在这里阅读有关Libev的更多信息。

    LibEio是一个异步执行输入输出的库。它处理文件描述符、数据处理程序、套接字等。您可以在此处阅读更多信息。

    LibUv是libeio、libev、c-ares(用于DNS)和iocp(用于windows异步io)之上的抽象层。LibUv执行、维护和管理事件池中的所有io和事件。(对于libeio线程池)。你应该看看Ryan Dahl的libUv教程。这将使您对libUv自身的工作方式有更多的了解,然后您将了解节点的工作方式。js在libuv和v8之上运行。

    要了解javascript事件循环,您应该考虑观看这些视频

    • JS-会议
    • JSConf2011 ( 有很刺激的sfx)
    • 了解事件驱动编程
    • 了解节点.js事件循环

    要了解如何使用libeio和node.js来创建异步模块,您应该看看这个例子。

    基本上是节点内部发生的情况。js是v8循环运行并处理所有javascript部分以及C模块[当它们在主线程中运行时(根据官方文档node.js本身是单线程的)]。当在主线程之外时,libev和libeio在线程池中处理它,libev提供与主循环的交互。根据我的理解,node。js有一个永久事件循环:这是v8事件循环。为了处理C异步任务,它使用线程池[通过libeio

    例如:

    eio_custom(Task,FLAG,AfterTask,Eio_REQUEST);
    

    出现在所有模块中的通常是调用线程池中的函数 Task。完成后,它会在主线程中调用 AfterTask 函数。而Eio_REQUEST是请求处理程序,它可以是一个结构/对象,其动机是提供线程池和主线程之间的通信。

  •  类似资料:
    • 问题内容: nodejs体系结构内部是否存在两个事件循环? libev / libuv v8 javascript事件循环 在I / O请求上,节点是否将请求排队到libeio,而libeio又通过使用libev的事件通知数据的可用性,最后这些事件由v8事件循环使用回调来处理? 基本上,libev和libeio如何集成到nodejs架构中? 是否有任何文档可以清楚地了解nodejs内部体系结构?

    • 本文向大家介绍详解nodejs异步I/O和事件循环,包括了详解nodejs异步I/O和事件循环的使用技巧和注意事项,需要的朋友参考一下 事件驱动模型 现在我们来看看nodejs中的事件驱动和异步I/O是如何实现的. nodejs是单线程(single thread)运行的,通过一个事件循环(event-loop)来循环取出消息队列(event-queue)中的消息进行处理,处理过程基本上就是去调用

    • 事件是应用程序与自身各个功能模块以及与操作系统进行通讯的手段,也是实现事件驱动编程模型的基础,应用程序如果要响应这些事件,通常是创建一个事件队列来集中存放它们,从事件队列取出事件并调用对应处理器就是一次事件响应,而往复执行这个操作的过程就是事件循环。 驱动接口 LCUI 对事件循环的操作有处理事件、绑定事件和解绑事件,驱动模块的职责就是基于操作系统接口向 LCUI 提供实现了这些操作的接口。首先我

    • 主要内容:事件驱动程序,实例,Node 应用程序是如何工作的?Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。 Node.js 几乎每一个 API 都是支持回调函数的。 Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。 Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发

    • 问题内容: Node.js I / O事件循环是单线程还是多线程? 如果我有多个I / O进程,则节点会将它们置于外部事件循环中。它们是按顺序处理(最快),还是处理事件循环以同时处理它们(…以及哪些限制)? 问题答案: 事件循环 Node.js事件循环在单个线程下运行,这意味着您编写的应用程序代码在单个线程上进行评估。Nodejs本身在libuv之下使用了许多线程,但是您在编写nodejs代码时不

    • Node.js 是单进程单线程应用程序,但是因为 V8 引擎提供的异步执行回调接口,通过这些接口可以处理大量的并发,所以性能非常高。 Node.js 几乎每一个 API 都是支持回调函数的。 Node.js 基本上所有的事件机制都是用设计模式中观察者模式实现。 Node.js 单线程类似进入一个while(true)的事件循环,直到没有事件观察者退出,每个异步事件都生成一个事件观察者,如果有事件发