定时器方案红黑树,时间轮,最小堆

 

 

腾讯面试题:

定时器误差大,该怎么处理?

答:利用定时信号加上定时器来解决。采用红黑树,定时信号打断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.多层级 

posted @ 2022-11-17 20:04  放弃吧  阅读(272)  评论(0编辑  收藏  举报