腾讯面试题:
定时器误差大,该怎么处理?
答:利用定时信号加上定时器来解决。采用红黑树,定时信号打断epoll_wait。多线程情况下,单起一个线程做定时
定时器的本质是越近要触发的定时任务,他的优先级越高。
定时器在单独一个线程进行检测
用什么数据结构来做定时器?
1. 红黑树 nginx(nginx最多组织1024个定时器)
2.最小堆 大部分项目 libevent(最小二叉堆)、go(最小四叉堆)、libev(最小四叉堆)四叉堆有百分之五的提升
3.时间轮 netty kafka skynet linux
红黑树和最小堆单线程,(因为加锁要加整棵树,效率低,所以采用单线程,少量定时器,小于1024)
时间轮多线程
加锁:时间轮用spinlock,因为时间复杂度低,O(1), 所以采用自旋锁。
设计一个定时器,需要哪些功能?
1. 初始化定时器
2.添加定时任务
3.删除定时任务
4.检测定时任务
不同数据结构有什么共性?
能够快速找到这个节点,增加删除。
能够快速找到最小的节点。
如果采用红黑树,怎么解决相同时间的节点?
nginx上是如果相同就插入在这个节点的右子树
删除节点?
删除红黑树最左边的节点。
检测定时任务?
检测红黑树最左边的节点key是否小于当前时间,如果是,就执行回调函数,然后删除此节点。
最小堆
满二叉树:所有的层节点数都是该层所能容纳节点的最大数量(满足2^n).
完全二叉树:若二叉树的深度为h,除了h层外,其他层的节点数都是该层所能容纳节点的最大数量,且h层都集中在最左侧;
1. 是⼀颗完全⼆叉树;
2. 某⼀个节点的值总是⼩于等于它的⼦节点的值;
3. 堆中每个节点的⼦树都是最⼩堆;
层序遍历:
某个节点:x
左子树索引:2x+1
右子树索引:2x+2
父节点索引:floor((x-1)/2)
最小堆:只关注父子的大小关系,不关注兄弟之间的大小关系
增加节点只有上升:先把新增的节点放到最后,然后与父节点 上升
删除节点:先与最后一个节点调换位置,删除,然后将换后的节点与最小的子节点换位置(有下降的情况也有上升的情况,比如删除9节点)
最小堆的稳定性更好
时间轮
多层级的时间轮
单层级时间轮
限流和熔断
单层时间轮设置时间轮大小,比如10秒一检测,就设置最小超过这个数的2^n,即16,设置这个原因是取余比较快,x % 2^n == x & (2^n - 1).。如果设置的太多,会产生空推进(有很多没有定时任务)的问题:最小堆+单层级时间轮
从x到(x+10) % 2^n刚好是10
如果小于检测周期,容易检测到还没过期的值。
空推进的解决方法:
1.最小堆
2.多层级
标签:定时器,删除,最小,红黑树,定时,节点 From: https://www.cnblogs.com/cuijy1/p/16600009.html