For investors
股价:
5.36 美元 %For investors
股价:
5.36 美元 %认真做教育 专心促就业
定时器设计是大多数软件编程开发程序员都需要熟练掌握的一个编程知识点,而本文我们就通过案例分析来简单了解一下,定时器设计常用方法都有哪些。
既然要使用定时器,必然离不开定时器的设计,那么如何设计定时器,成为接下来需要解决的问题。
接口设计
先是接口的设计
基本接口:
初始化定时器:voidinit_timer();
添加定时任务:Node*add_timer(intexpire,callbackcb);
删除定时任务:booldelete_timer(Node*node);一般在检测定时器的时候使用,可以不对外提供该接口;
找到近的需要被触发的定时任务:Node*find_nearest_timer();这种接口一般应用于网络事件和定时事件在一个线程中处理的触发方式。
检测更新所有定时任务:voidupdate_timer();
清除所有定时任务:voidclear_timer();
内部数据结构选择
对外提供的接口解决了,那么接下来该思考定时器内部该用什么样的数据结构维护定时任务会让效率达到佳;
该数据结构需要满足一些条件,比如查询小节点的时间复杂度比如得小,比如增加删除节点不会影响原有的数据结构。
因此选择出来了,红黑树、小堆都是佳的选择。
红黑树
红黑树的中序遍历,让数据可以有序排序,而且是绝对排序(从小到大排序)。具体数据结构,可以去查找网上其他资料。
增删查的时间复杂度均为O(logN);
小的节点为红黑树左侧的节点,时间复杂度O(logN);
如果几乎同时来个两个时间相等的任务,但是key值比较时会出现相等的情况,你可以把后来的任务放到其右节点位置。
小堆
小堆是一个完全二叉树,且父节点一定比子节点小,这样得到的结果就是根节点一定是这棵树的小值;具体数据结构,可以去查找网上其他资料。
增查的时间复杂度O(logN);
删除操作需要查找是否包含这个节点,删除的时间复杂度O(n);
小节点的时间复杂度为O(1);
时间轮
以上两种实现方法需要时时刻刻都要进行检测,对于定时任务密集类型的自然可以,如果是定时任务之间的间隔时间过长怎么办?时时刻刻检测会增加很多无效检测,降低cpu的使用效率。
使用时间轮是一种解决上述问题的方法;
时间轮需要保证自己的时间精度足够小,否则会出现不能插入定时任务的情况
单层级时间轮
先先谈一谈单层级时间轮,单层级时间轮就是使用数组模拟一个环形队列,数组的每一个元素是一个定时任务链表。通过一个指针不断遍历这个数组,遇到某个元素的任务链表不为空就执行相应的任务。
对于单层级时间轮需要数组的大小足够大,否则插入的定时任务超出数组可关注时间(比如时间精度1ms,数组大小为20,可关注的时间就是20ms)的N多倍,会导致定时任务执行顺序出错。(不确定在定时任务的结构体增加一个圈数可不可以);
多层级时间轮
那么多层级时间轮就是解决上述问题一个好的解决办法。类似于进制进位一样,一旦超过该层级的可关注时间,就会进入下一层级,直到有位置可以插入;如果某个定时任务即将执行,也会不断返回上一层级,直至挂载到一层级(也是被执行层级)。
如果使用时间轮也是直接使用多层级时间轮的,它有以下这些优点:
相比于单层级时间轮,它的空间占用大大减少;因为多层级针对任务的时间储存是乘的关系,而单层级是加的关系
对于多层级,除去一层的任务需要时时刻刻关注,其他层的元素每增加一次重新映射一次即可。
【免责声明】本文系本网编辑部分转载,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如涉及作品内容、版权和其它问题,请在30日内与管理员联系,我们会予以更改或删除相关文章,以保证您的权益!请读者仅作参考。更多内容请加抖音太原达内IT培训学习了解。