高效定时器的设计

一、timerfd

  调用timerfd_create()创建一个时间文件描述符即把时间变为文件描述符,定时器超时则文件描述符会变得可读,这样可以和epoll结合起来,统一处理I/O事件和超时事件。可以把timerfd和时间戳一起作为key,避免两个定时器相同的情况

二、定时器的概念

  网络编程中应用层的定时器是很有必要的,这可以让服务端主动关闭时间很久的非活跃连接。另外一种解决方案是TCP的keepalive,但它只能检测真正的死连接,即客端主机断电,或者网线被拔掉这种情况。如果客端连接上,但什么都不做,keepalive是毫无办法的,它只能一定时间后不断的向客户端发送心跳包

  在开发高性能服务器中,定时器总是不可或缺的, 常见的定时器实现三种,分别是:排序链表,最小堆,时间轮
在这里插入图片描述

三、排序链表

  升序定时器链表(使用双向链表)将定时器按照超时时间做升序排序,心博函数从头结点开始一次处理每个定时器,直到遇到一个尚未到期的定时器,然后调用定时器超时回调函数,以执行定时任务。
在这里插入图片描述

  这种定时器设计的缺点在于,添加一个定时器的复杂度是O(n),因为要保持有序性,所以需要遍历链表插入到合适的位置。假设系统有大量的定时器(10W个)使用升序链表型的就会有性能问题。

四、最小堆(优先队列)

  堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左子节点和右子节点的值

  由于堆是一种经过排序的完全二叉树,因此在构建的时候需要对新插入的节点进行一些操作以使其符合堆的性质。这种操作就是节点的上浮与下沉。

  由于定时器的触发是由于时间到了,因此只有时间最短的定时器会首先被触发,通过这个原理,我们可以采用最小堆,将按时间顺序排序,堆顶元素是时间最短的定时器,因此只要判断堆顶元素是否被触发即可。只有堆顶定时器的时间到了,才会到其他时间较晚的定时器的时间。
在这里插入图片描述
【特点】:

  • 最小堆一般是采用堆的方式实现,元素访问速度远高于采用链表方式的红黑树,插入性能快红黑树好几倍,但最小堆的删除性能并不快于红黑树

  • 最小堆的最大缺点就在于必须是连续的内存

五、时间轮(环形队列+双向链表)

  时间轮简介:时间轮方案将现实生活中的时钟概念引入到软件设计中,主要思路是定义一个时钟周期和步长(比如时钟的一秒走一次),当指针每走一步的时候,会获取当前时钟刻度上挂载的任务并执行
在这里插入图片描述
  以上图为例,假设一个格子为1秒,整个一圈表示的时间为12秒,此时需要添加5秒后执行的任务,则此时改任务一个放到第(1+5=6)的格子内,如果此时添加13秒后执行任务,此时该任务应该等转完一圈后round为1 放到第二格子中,指针每转动一个一格,获取当前round为0的任务执行,格子上的其他任务round减1 。问题:当时间跨度很大,数量很大时,单层的时间轮造成的round很大,一个格子中链很长,所以衍生出多级时间轮的设计方案
在这里插入图片描述
  假设图中每层轮子为20个格子,第一层轮子最小时间间隔为1ms,第二层为20ms,第三层为400ms,此时添加5ms后执行的任务,此时应该添加到第一层的第5格子中。如果此时添加445ms后执行的任务,则第一层表示的时间跨度不够,第二层表示的时间跨度也不够,第三层表示的时间跨度足够,该任务应该放到第三层轮子第二格子中,该轮子指针指到第二格子中时,计算离任务启动时间还有多长时间,慢慢将该任务移动到底层轮子上,最终任务到期执行。

【特点】:

  • 是任务的添加与移除,都是O(1)级的复杂度;

  • 不会占用大量的资源;

  • 只需要有一个线程去推进时间轮就可以工作了。

五、红黑树(std::set自动排序)

在这里插入图片描述
  Nginx定时器实现的核心是使用一棵红黑树来存储各个定时事件,每次循环的时候就从这棵树里找出超时的事件,然后一一触发,完成定时任务操作。

  红黑树插入是最坏情况要比较2logN次(最高的高度)外加不超过两次旋转,最小堆最坏情况是logN次;红黑树删除不需要比较只需要不超过3旋转,查找最小值需要遍历logN

参考:https://blog.csdn.net/FreeeLinux/article/details/54884771
https://blog.csdn.net/u010939285/article/details/80049412

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值