libuv 原理_Libuv初理解

libuv是一个跨平台库,专为Node.js设计,基于事件驱动的异步I/O模型。核心是I/O循环,使用handles和requests抽象,支持不同平台的I/O轮询机制。handles处理长时间活跃的对象,requests则代表短期操作。libuv利用线程池实现异步文件I/O,网络I/O则在单线程中执行。
摘要由CSDN通过智能技术生成

整体概念

libuv是一个跨平台、专门写给nodejs的库,它的设计是围绕着事件驱动的异步I/O模型。在不同的I/O轮询机制上,libuv提供的不是简单抽象对象:handle和streams为sockets和其他实例提供了一个高级抽象。此外,libuv还提供了跨平台文件I/O和线程化功能

这里有一个图表,说明了构成libuv的不同部分以及它们与什么子系统相关:b5f0f77fd5939b5349723f86e9d1c7d2.png

handles和request

libuv给用户提供了2个可操作的抽象对象,evnt loop的组合:handles和requests。

handles能够操作那些长时间活跃的对象,例如:

活跃的handle在每一次event loop期间会被调用一次循环迭代

tcp服务会回调一次连接服务当一个新的连接过来时

requests代表的是短时间活跃的操作。这些操作可以被表现依赖于handle上:写请求用来在handle上写数据。或者独立的:像getaddrinfo请求就不需要依赖handle,可以自己独立在event loop中执行

I/O循环

I/O或者说event loop是libuv的核心。它为所有I/O操作创建了内容,也就意味着这些操作绑定在了某一个单一的线程上。只要每个线程运行在不同的线程中,就可以运行多个事件循环。不过libuv的event loop不是一个安全的线程

event loop遵从一个单一异步I/O线程方法:所有的(网络)I/O必须执行在一个没有被阻塞的sockets中,使用给定平台上可用的最佳机制进行轮询(例如:Linux的epoll、OSX的kqueue和其他的一些BSDs、SunOs的事件接口和windows上的IOCP)。作为循环迭代的一部分,loop会被阻塞,等待已经添加到poller和回调的sockets上的I/O活动,此时将触发sockets状态(可读、可写的挂起),因此handle可以读取、写入或执行所需的I/O操作。

为了更好的理解event loop的操作,下图将展示所有循环迭代(loop iteration)的状态

bf2fd8151d78b0d282cc431fc12e1ef4.png

1.“now”的循环概念得到了更新。事件循环在事件循环开始时缓存当前时间,以减少与时间相关的系统调用的数量。

2.如果循环是活跃的,则会启动循环迭代,否则循环将立即退出。那么,什么时候被认为是活跃着的循环呢?如果一个循环有活动和ref自己的handles,主动请求或关闭句柄被认为是有活跃着的。

3.由于计时器运行。所有活跃着的时间调度器都安排在循环的now概念之前调用他们的回调函数

4.挂载的回调函数将被调用。所有I/O回调函数都是在轮询event loop的poll之后被调用的。但是,存在一些特殊情况:比如调用这样的回调被推迟到下一个循环迭代中调用,那么此时就可能立刻执行上一个event loop中延迟的I/O回调函数。

5.调用idle handle回调函数被调用。尽管这个名称不是很好听,但如果idle handle是活跃的,那么再每次event loop过程中都一定会调用

6.调用prepare handle的回调函数。Prepare handles的回调函数在I/O之前

7.poll阶段计算延迟时间。在阻塞I/O之前,loop去计算它应该阻塞多长时间。这些是计算超时时的规则:

如果loop运行的flag是UV_RUN_NOWAIT,延迟时间为0

如果loop是被uv_stop阻塞,则延迟0

如果此时没有活跃的handles和requests,延迟为0

如果此时有任何活跃着的idel handles,则延迟0

如果此时有任何处于pending状态的handles被关闭,则延迟为0

如果上述任何情况都没有,则调用最近的timeout,如果没有任何活跃的时间timer存在,则无限延迟

8.在I/O阶段阻塞。在这个时候,the loop将阻塞I/O,用于在上一步中计算的持续时间。所有正在监视一个读或写操作的给定文件描述符的I/O相关handles将在此处调用它们的回调。

9.调用check handle的回调。check handle在I/O阶段之后调用。

10.调用CLose的回调函数。如果一个handes被uv_close()函数调用关闭,那么close的回调函数就会被调用

11.在使用UV_RUN_ONCE模式这个特殊情况下运行,I/O可能没有回调函数存在在I/O被阻塞之后去调用,而有timers到期,从而回调了timers的回调函数

12.循环结束。如果loop是运行在UV_RUN_NOWAIT或者UV_RUN_ONCE模式下的运行结束,那么就uv_run()方法会被返回。如果运行在UV_RUN_DEFAULT模式下,且the loop在结束的时候仍然活着,那么将会继续运行,并且从头开始循环迭代,否则也将会结束

在每次循环线程中,libuv使用线程池实现异步文件I/O操作,但是网络I/O总是在单个线程中执行。

I/O文件

不像网络I/O,没有特定于平台的文件I/O原语libuv可以依赖,所以当前的方法是在线程池中运行阻塞文件I/O操作。

libuv目前使用的是一个全局线程池,其中所有循环都可以在其中进行队列工作。3种操作目前在此池中运行:

文件系统操作

DNS功能(getaddrinfo和getnameinfo)

用户通过uv_queue_work()指定的代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值