这是我参与8月更文挑战的第16天,活动详情查看:8月更文挑战
重数据结构来划分,常见的定时器设计一般有 排序链表、红黑树和时间轮、最小堆等。
对于第一种排序链表,就是每次插入任务的时候,按照时间的先后进行插入定时任务,从而达到实现定时执行函数的功能。
而第二种,红黑树,可以在 nginx 中看到相关的实现,利用红黑树的时间优势,可以做到高精度低延迟的定时器。
第三种可以在Linux 中刚看到相关实现,其本质是利用循环链表,但实现起来其实要更复杂一点。属于优点缺点都很明显的设计。
从时间方面来看,定时器也可以分成两种,一种是绝对时间,一种是相对时间。往往在硬件环境和软件环境中,由于时间精度可以自己调整,所以相对时间的选择比较多,而且选择绝对时间,也就是利用系统时间的实现,还需要处理系统发生篡改时间的情况,处理起来较为复杂。
执行到期任务的时候也有几种选择:
依赖事件循环,例如 libhv:github.com/ithewei/lib…
static int hloop_process_timers(hloop_t* loop) { | |
| ------------------------------------------------ | -------------------------------------------------------------------------------------------- |
| | int ntimers = 0; |
| | htimer_t* timer = NULL; |
| | uint64_t now_hrtime = hloop_now_hrtime(loop); |
| | while (loop->timers.root) { |
| | // NOTE: root of minheap has min timeout. |
| | timer = TIMER_ENTRY(loop->timers.root); |
| | if (timer->next_timeout > now_hrtime) { |
| | break; |
| | } |
| | if (timer->repeat != INFINITE) { |
| | --timer->repeat; |
| | } |
| | if (timer->repeat == 0) { |
| | // NOTE: Just mark it as destroy and remove from heap. |
| | // Real deletion occurs after hloop_process_pendings. |
| | __htimer_del(timer); |
| | } |
| | else { |
| | // NOTE: calc next timeout, then re-insert heap. |
| | heap_dequeue(&loop->timers); |
| | if (timer->event_type == HEVENT_TYPE_TIMEOUT) { |
| | while (timer->next_timeout <= now_hrtime) { |
| | timer->next_timeout += (uint64_t)((htimeout_t*)timer)->timeout * 1000; |
| | } |
| | } |
| | else if (timer->event_type == HEVENT_TYPE_PERIOD) { |
| | hperiod_t* period = (hperiod_t*)timer; |
| | timer->next_timeout = (uint64_t)cron_next_timeout(period->minute, period->hour, period->day, |
| | period->week, period->month) * 1000000; |
| | } |
| | heap_insert(&loop->timers, &timer->node); |
| | } |
| | EVENT_PENDING(timer); |
| | ++ntimers; |
| | } |
| | return ntimers; |
| | }
不依赖事件循环,列如,用一个列表记录定时器,每当处理函数被调用时从列表取出已超时的定时器,然后调用这些定时器的回调函数。这种情况就需要将定时器中,一般设置为static 的变量重外部导入。