当前位置:网站首页>Libuv库 - 设计概述(中文版)
Libuv库 - 设计概述(中文版)
2022-07-03 12:45:00 【ufgnix0802】
Libuv库 - 设计概述
以下为libuv官网Design overview的中文翻译。
http://docs.libuv.org/en/v1.x/design.html
libuv是一个跨平台的支持库,原先只是为Node.js而编写。它是围绕事件驱动的异步I/O模型而设计的。
该库提供的不仅仅是在不同I/O轮询机制上的简单抽象,而且”handles“和”stream“的出现为sockets和其它实体提供了一个更加高级的抽象。还有跨平台的I/O文件和线程功能等更多的功能。
以下是一张图表,说明了构成libuv的不同部分以及它们与相应子系统的关系:
TIPS:
以下内容是对于上述图表内容进行解释,转载至:https://toutiao.io/posts/9ucbgr/preview
从左往右分为两部分,一部分是与NetWork I/O相关的请求,而另外一部分则是由FIle I/O、DNS Ops以及User code组成的请求。从图中可以看出,对于NetWork I/O和File I/O为代表的每一类请求,异步处理的底层支持机制是完全不一样的。对于NetWork I/O相关的请求,根据OS平台的不同,由不同对的底层支持机制,如Linux上使用epoll,OSX和BSD类系统使用kqueue,SunOS上是使用的是event ports以及Windows上使用的是IOCP机制。而对于File I/O为代表的请求,则使用Thread pool。利用Thread pool的方式实现异步请求处理,在各类OS上都能获得很好的支持。
在文章:https://blog.libtorrent.org/2012/10/asynchronous-disk-io/中详细描述了对于disk I/O,Libuv团队为什么要选择thread pool的机制。基本上原因不外乎编码和维护复杂度太高、可支持的API太少且质量堪忧、技术支持较弱,而用thread pool则很好地避开了这些问题。这是一篇很有意思的文章,从中可以看出libuv团队当时实现跨平台异步兼容所作出的各种研究和幸苦尝试。
Handles 和 requests
libuv结合event loop为用户提供了两个抽象,分别是handles 和 requests。
Handles代表长期存活的对象,能在活跃时期处理指定事件。比如:
- 每一次事件轮询时,活跃的prepare handle的回调事件都会被调用。
- 每次有新的连接到来时,TCP服务端的handle的连接请求回调发都会被调用。
requests通常表示短期存活的操作。这些操作都是通过handle实现的,write requests是通过handle去写数据,或者无需handle也可写数据。getaddrinfo requests也不需要handle,而是直接运行在loop上。
I/O 轮询
I/O(或者事件)轮询是libuv的核心部分。它构成了所以的I/O操作,意味着它是单线程的。libuv是可以运行多个event loop的,只要为每一个event loop创建一个线程即可(即多个事件轮询意味着多线程)。libuv的事件循环(主要指跟轮询和handle相关的API)是线程不安全的。除非有另外其它的说明。
这个event loop遵循的是非常流行的单线程异步I/O模型:所有的(网络)I/O均是基于非阻塞的socket来实现的,并且这些socket使用的是给定平台上可用的最佳机制进行轮询的,比如Linux平台上使用epoll模型、OSX和BSD类系统使用kqueue、SunOS系统使用的是event ports和Windows平台使用的是IOCP。作为事件轮询的一部分,循环将阻塞于等待socket I/O事件上。已经添加到轮询机制中的socket I/O事件的回调事件将在socket条件(可读/可写条件)被触发时调用,从而使得handle能够读写数据,或者执行I/O操作。
为了更好地理解事件轮询的运行机制,以下图中说明了循环轮询的所有阶段:
- 更新loop的时间戳。在每次事件轮询开始时,loop都会缓存当前时间。这是为了减少与时间相关的系统调用次数。
- 如果loop依然活跃,那么我们继续轮询,否则我们退出轮询。那么如何判断loop处于活跃状态呢?只要loop中还有活跃的和被引用的handle、活跃的request、关闭中的handle,都被认为loop仍然处于活跃状态。
- 所有到期的定时器都被执行。所有时间已超过loop时间戳的活跃定时器中的相应回调事件都别调用。
- pending的回调事件被调用。大部分I/O回调事件是在I/O轮询后立即调用的;但是那些在上一次事件轮询中需要延迟到下一轮事件轮询的I/O回调,就是在这个时候被调用的。
- idle handle的回调事件被调用。在每次事件轮询中,活跃的idle handle都会被运行。
- prepare handle的回调事件被调用。prepare handle的回调时在I/O轮询之前被调用的。
- 计算轮询的超时时间。在阻塞I/O之前,loop需要计算它该阻塞多久。计算超时时间的规则如下:
- 超时时间设置为0,如果loop是以UV_RUN_NOWAIT模式运行。
- 如果loop已停止(调用uv_loop()事件)。超时时间设置为0。
- 如果没有活跃的handle或者request。超时时间设置为0。
- 如果存在需要延迟关闭的handle。超时时间设置为0。
- 除此之外,如果有活跃的定时器,超时时间设置为最接近定时器的时间,否则超时时间无限长。
- I/O的loop模块。此时,在上一步计算的持续时间内,循环将阻塞在这段时间内。这个过程中,所有正在监视给定文件描述符的I/O相关的handles都会在这个时候调用它们的回调事件。
- 调用检查handle的回调事件。检查handle的回调事件是在I/O轮询之后被调用的。check handle和prepare handle正式loop中的对等部分。
- 关闭回调被调用。如果handle关闭是由于调用了uv_close(),那么将会调用关闭回调事件。
- 特别的是,如果loop是以UV_RUN_ONCE的模式进行轮询的,在I/O轮询之后可能没有I/O回调被调用。但是超时的定时器的回调事件会被调用。
- 轮询结束,如果loop运行的模式为UV_RUN_NOWAIT或者UV_RUN_ONCE,那么此时uv_run()就会返回结果,如果loop运行的模式为UV_RUN_DEFAULT,那么将会进行下一次轮询。
TIPS:libuv使用线程池来使异步文件I/O操作成为可能,但是网络I/O始终在单个线程中执行每个循环的线程。
注意,虽然不同平台有不同的轮询机制,但是libuv在Unix和Windows系统保持一致的运行模式。
文件I/O
与NetWork I/O不同,libuv没有平台相关的文件I/O机制可以依赖,所以当前的方式是在线程池中处理阻塞的I/O文件操作。
想要理解跨平台I/O文件的设计,可参考:https://blog.libtorrent.org/2012/10/asynchronous-disk-io/
libuv当前使用一个全局线程池,所有循环都可以排队工作。目前在线程池上运行了三种操作类型:
- 文件系统操作。
- DNS 函数(getaddrinfo 和 getnameinfo)
- 用户编写的代码通过uv_queue_work()运行。
边栏推荐
猜你喜欢
Image component in ETS development mode of openharmony application development
MySQL functions and related cases and exercises
OpenHarmony应用开发之ETS开发方式中的Image组件
2022-02-14 incluxdb cluster write data writetoshard parsing
MySQL_ JDBC
IDEA 全文搜索快捷键Ctr+Shift+F失效问题
【数据库原理及应用教程(第4版|微课版)陈志泊】【第四章习题】
When the R language output rmarkdown is in other formats (such as PDF), an error is reported, latex failed to compile stocks Tex. solution
[Database Principle and Application Tutorial (4th Edition | wechat Edition) Chen Zhibo] [Chapter IV exercises]
正则表达式
随机推荐
SQL learning notes (I)
对业务的一些思考
Logseq evaluation: advantages, disadvantages, evaluation, learning tutorial
Kotlin - 改良装饰者模式
[Database Principle and Application Tutorial (4th Edition | wechat Edition) Chen Zhibo] [Chapter IV exercises]
Red Hat Satellite 6:更好地管理服务器和云
解决 System has not been booted with systemd as init system (PID 1). Can‘t operate.
显卡缺货终于到头了:4000多块可得3070Ti,比原价便宜2000块拿下3090Ti
2022-01-27 redis cluster cluster proxy predixy analysis
已解决(机器学习中查看数据信息报错)AttributeError: target_names
Sword finger offer 12 Path in matrix
这本数学书AI圈都在转,资深ML研究员历时7年之作,免费电子版可看
35道MySQL面试必问题图解,这样也太好理解了吧
PostgreSQL installation
C graphical tutorial (Fourth Edition)_ Chapter 18 enumerator and iterator: enumerator samplep340
开始报名丨CCF C³[email protected]奇安信:透视俄乌网络战 —— 网络空间基础设施面临的安全对抗与制裁博弈...
PowerPoint tutorial, how to save a presentation as a video in PowerPoint?
Flink SQL knows why (12): is it difficult to join streams? (top)
sitesCMS v3.1.0发布,上线微信小程序
剑指 Offer 14- II. 剪绳子 II