📜  Node.js 中的 Libuv

📅  最后修改于: 2022-05-13 01:56:34.894000             🧑  作者: Mango

Node.js 中的 Libuv

Node.js 在底层依赖各种依赖项来提供各种功能。

  • V8
  • 库夫
  • llhttp
  • 战神
  • OpenSSL

libuv就是其中之一,下面我们来详细讨论一下libuv

libuv: libuv 是最初为 Node.js 编写的用于抽象非阻塞 I/O 操作的 C 库。

  • 集成了事件驱动的异步 I/O 模型。
  • 它允许在执行 I/O 操作的同时同时使用 CPU 和其他资源,从而有效地利用资源和网络。
  • 它促进了一种事件驱动的方法,其中 I/O 和其他活动是使用基于回调的通知来执行的。

示例:如果一个程序正在查询数据库,CPU 一直处于空闲状态,直到查询处理完毕,程序处于停止状态,从而造成系统资源的浪费。为了防止这种情况,在 Node.js 中使用了libuv ,它促进了非阻塞 I/O。

它还具有处理文件系统 DNS 、网络、子进程、管道、信号处理、轮询流式传输等服务的机制
为了执行无法在操作系统级别异步完成的阻塞操作,libuv 还包含一个线程池来分配 CPU 负载。

  • 什么是线程池?

Libuv 将任务分配给工作线程池。但是,任务完成时发生的所有回调都在主线程上执行。
注意: Node 10.5 之后的工作线程也可以用于并行执行 JavaScript。 Libuv 默认使用 4 个线程,但可以使用UV_THREADPOOL_SIZE更改

process.env.UV_THREADPOOL_SIZE = 5

libuv的特点:

  • 由 epoll (Linux)、kqueue (OSX)、IOCP (Windows)、事件端口 (SunOS) 支持的全功能事件循环。
  • 异步 TCP(net 模块)和 UDP(dgram 模块)
  • 异步 DNS 解析(部分用于 dns 模块)
  • 异步文件、文件系统操作和事件(fs 模块)
  • ANSI 转义码控制的 TTY
  • 线程池和信号处理
  • 子进程
  • 高分辨率时钟
  • 线程和同步原语。
  • 使用套接字和 Unix 域套接字的进程间通信 (Windows)

事件或 I/O 循环:事件或 I/O 循环使用单线程异步 I/O 方法,因此它与单个线程相关联。为了运行多个事件循环,这些事件循环中的每一个都必须在不同的线程上运行。默认情况下它不是线程安全的,但有一些例外。

Libuv 维护一个Event queueevent demultiplexer 。循环监听传入的 I/O 并为每个请求发出事件。然后将请求分配给特定的处理程序(取决于操作系统)。成功执行后,注册的回调会被排入事件队列中,事件队列会被一一连续执行。
注意:整个过程所需的当前时间由libuv在每次循环迭代开始时缓存,以尽量减少频繁的系统调用。

示例:如果发出网络请求,则为该请求注册回调,并将任务分配给处理程序。在执行之前,其他操作会继续进行。在成功执行/终止时,注册的回调在事件队列中排队,然后在执行队列中已经存在的先前回调之后由主线程执行。

它使用前面提到的特定于平台的机制来实现最佳的兼容性和性能epoll (Linux)、kqueue (OSX)、IOCP (Windows)、事件端口 (SunOS)。

文件 I/O:文件 I/O 在 libuv 中使用全局线程池实现,所有循环都可以在该线程池上排队工作。它允许以抽象的异步方式使用磁盘。它将复杂的操作分解为更简单的操作,以促进类似异步的行为。

示例:如果程序指示将缓冲区写入特定文件,在正常情况下,I/O 将被阻塞,直到操作成功/终止。但是,libuv 通过放置一个事件通知将其抽象为异步方式,该事件通知将在操作完成后通知操作成功/失败,直到那时其他 I/O 操作可以轻松执行。
注意: libuv 不保证线程安全(少数例外)

与事件循环不同,文件 I/O 使用独立于平台的机制。文件 I/O 处理 3 种异步磁盘 API

  1. linux AIO(内核支持)
  2. posix AIO(支持 linux、BSD、Mac OS X、solaris、AIX 等)
  3. Windows 的重叠 I/O

好处:

  • 磁盘操作是异步执行的。
  • 高级操作可以分解为更简单的磁盘操作,这有助于纠正信息。
  • 磁盘线程可以使用诸如 readv 和 writev 之类的向量操作,从而允许传递更多的缓冲区。

参考: http://docs.libuv.org/en/v1.x/design.html