为了账号安全,请及时绑定邮箱和手机立即绑定

Nodejs事件循环

Nodejs事件循环

凤凰求蛊 2019-07-31 14:38:36
Nodejs事件循环nodejs架构内部有两个事件循环吗?libev / libuvv8 javascript事件循环在I / O请求上,节点将请求排队到libeio,后者又通过使用libev的事件通知数据的可用性,最后这些事件是由v8事件循环使用回调来处理的吗?基本上,libev和libeio如何集成在nodejs架构中?有没有可用于提供nodejs内部架构清晰图片的文档?
查看完整描述

3 回答

?
喵喵时光机

TA贡献1846条经验 获得超7个赞

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

让我尝试在抽象的UNIX环境中,在Node的上下文中,借助抽象示例来解释事件驱动模型的工作。

计划的观点:

  • 脚本引擎开始执行脚本。

  • 每当遇到CPU绑定操作时,它都会在内联(真实机器)中完成。

  • 每当遇到I / O绑定操作时,请求及其完成处理程序都会在“事件机器”(虚拟机)中注册

  • 以相同的方式重复操作,直到脚本结束。CPU绑定操作 - 执行内联,I / O绑定操作,如上所述向机器请求。

  • 当I / O完成时,将回调一下监听器。

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

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,并且发出它们的回调。一个接一个地。

  • 尚未准备好的那些(例如套接字读取,另一个端点尚未写入任何内容)将继续用OS进行探测,直到它们可用。

  • 循环内部维持一个不断增加的计时器。当应用程序请求延迟回调(例如setTimeout)时,将利用此内部计时器值来计算触发回调的正确时间。

虽然大多数功能都以这种方式迎合,但文件操作的一些(异步版本)是在附加线程的帮助下执行的,并且很好地集成到libuv中。虽然网络I / O操作可以等待期望外部事件,例如另一个端点响应数据等,但文件操作需要来自节点本身的一些工作。例如,如果你打开一个文件并等待fd准备好数据,它就不会发生,因为没有人正在阅读!同时,如果您从主线程中的内联文件中读取,它可能会阻止程序中的其他活动,并且可能会产生可见问题,因为与cpu绑定活动相比,文件操作非常慢。因此,内部工作线程(可通过UV_THREADPOOL_SIZE环境变量配置)用于对文件进行操作,

希望这可以帮助。


查看完整回答
反对 回复 2019-07-31
?
眼眸繁星

TA贡献1873条经验 获得超9个赞

ibuv简介

该Node.js的项目开始于2009年从浏览器分离一个JavaScript环境。使用谷歌的V8和Marc Lehmann的libev,node.js将I / O模型 - 偶数 - 与一种非常适合编程风格的语言相结合; 由于浏览器的形成方式。随着node.js越来越流行,让它在Windows上运行很重要,但libev只能在Unix上运行。Windows等效的内核事件通知机制(如kqueue或(e)轮询)是IOCP。libuv是一个围绕libev或IOCP的抽象,取决于平台,为用户提供基于libev的API。在node-v0.9.0版本的libuv中,libev被删除了。

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

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


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



   ┌───────────────────────┐

┌─>│        timers         │

│  └──────────┬────────────┘

│  ┌──────────┴────────────┐

│  │     I/O callbacks     │

│  └──────────┬────────────┘

│  ┌──────────┴────────────┐

│  │     idle, prepare     │

│  └──────────┬────────────┘      ┌───────────────┐

│  ┌──────────┴────────────┐      │   incoming:   │

│  │         poll          │<─────┤  connections, │

│  └──────────┬────────────┘      │   data, etc.  │

│  ┌──────────┴────────────┐      └───────────────┘

│  │        check          │

│  └──────────┬────────────┘

│  ┌──────────┴────────────┐

└──┤    close callbacks    │

   └───────────────────────┘


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


阶段概述


定时器:此阶段执行由setTimeout()和调度的回调setInterval()。

I / O回调:除了执行几乎所有回调之外

关闭回调,由计时器安排的回调,和setImmediate()。空闲,准备:仅在内部使用。

poll:检索新的I / O事件; 节点将在适当时阻止此处。

check:setImmediate()在这里调用回调。

关闭回调:例如socket.on('close', ...)。

在事件循环的每次运行之间,Node.js检查它是否在等待任何异步I / O或定时器,如果没有,则检查是否干净。


查看完整回答
反对 回复 2019-07-31
  • 3 回答
  • 0 关注
  • 728 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信