在看 Node http 模块文档的时候, 才留意到
server.timeout
这个属性, 本想简单介绍一下, 但是在梳理过后发现关于timeout
有庞大的内容支撑:server.timout -> node core timers -> uv timers -> linux msleep/hrtimer -> clocksource -> tsc -> cmos rtc -> clock cycle
, 所以拆分成几部分大致做下介绍, 期望定时器系列结束之后, noder 能够大致明白:clock cycle
是如何驱动 linux 的msleep/hrtimer
; linux 的 timers 与 uv timers 的关系; node timers 与 uv timers的关系。
Nodejs 的timer能力是依赖于Libuv提供的能力,那Libuv的timer是本身提供了哪些能力?又依赖于Linux哪些能力呢?
数据结构
在Linux中,与timer相关的数据结构有用于高精度定时器的红黑树
和用于低精度的分桶-链表
, Libuv中与定时器相关的数据结构是最小堆
,其实Nodejs中与定时器相关的数据结构也是最小堆和双向链表
。
最小堆的特点是获取最小值的时间复杂度为O(1),可以快速获取总多定时器中的最小值。在 Linux 中将最小值的cycles设置到APIC中,剩下的就是坐等被调用
,那libuv 是如何处理的呢?
工作原理
Linux提供了一种同步非阻塞的系统调用函数epoll-epoll(fd, type, timeout),可以在指定时间到期后继续执行。Libuv中关于timer的大概执行原理如下:
const minHeap = new MinHeap(); // 小头堆
// Timer(timeout, handler)
const timer1 = new Timer(10s, () => {print('时间到')}); // 10秒定时器
const timer2 = new Timer(100s, () => {print('时间到')}); // 100秒定时器
minHeap.insert(timer1).insert(timer2); // 压入小头堆
while(minHeap.isEmpty()) {
const minTimer = minHeap.peek();// 获取最小堆里的最小时间
epoll(..., minTimer.timeout);// 同步非阻塞调用
minTimer.handler(); // 执行定时任务
minHeap.remove();// 删除最小值
} // 直到定时器最小堆为空, 退出执行
每次循环取出需要等待的最小值,然后调用同步非阻塞系统调用函数,等待超时后继续执行,然后执行定时回调, 再次进入循环。由此可见 libuv 提供数据结构和业务逻辑
,Linux 提供了同步非阻塞系统调用。最神秘的还是epoll调用,那它是如何实现的呢?
调试uv
在阅读源码的过程中,亲自调试
一次可以起到事半功倍的效果,因为个人在编译的过程中也踩了很多坑,也简单记录下, 所以暂且放下 epoll 黑盒子,先说下调试过程。
准备程序 test.c
#include "stdio.h"
#include "uv.h"
static int timer_cb_called;
static void timer_cb(uv_timer_t* handle) {
timer_cb_called++;
}
int main() {
uv_loop_t *loop = uv_default_loop();
uv_timer_t timer_req1;
uv_timer_t timer_req2;
uv_timer_init(loop, &timer_req1);
uv_timer_init(loop, &timer_req2);
uv_timer_start(&timer_req1, timer_cb, 1e4, 0);
uv_timer_start(&timer_req2, timer_cb, 1e6, 0);
uv_run(loop, UV_RUN_DEFAULT);
编译 libuv
./configure --prefix=指定库文件安装的目录
make
make install
个人在调试过程中觉得第一步非常重要,不要使用默认目录
编译用户代码
gcc test.c -I ./include/ -L 指定库文件安装的目录 -luv -g -o test
个人把test.c放到了libuv目录下编译的
gdb 调试
gdb --args test
神秘的 epoll
epoll 怎么就这么🐮呢,以目前有限的知识大胆猜测,它应该也是利用了Linux的定時器,因为它的精度是ms,所以猜测应该利用了低精度定时器。由于篇(还)幅(没)有限(看),且等下篇。
关注我的微信公众号"SUNTOPO WLOG",欢迎留言讨论,我会尽可能回复,感谢您的阅读。