• 忘掉天地
  • 仿佛也想不起自己
bingliaolongBingliaolong  2021-12-18 00:36 Aet 隐藏边栏 |   抢沙发  6 
文章评分 2 次,平均分 5.0

高性能定时器

时间论

  1. 基于排序链表的定时器存在一个问题:添加定时器的效率偏低
    时间论解决了这个问题

  1. 上图所示时间论,(实线)指针指向轮子的一个槽(slot)。
    它恒定的速度顺时针转动,每转动一步就指向下一个槽(虚线指向的槽),每次转动称为一个滴答(tick)。

  2. 一个滴答的时间称为时间论的槽间隔si,它实际上就是心搏时间。
    该时间论共有N个槽,因此它转动一周的时间是N*si。

  3. 每个槽指向一条定时器链表,每条链表上的定时器具有相同的特征:它们的定时时间相差N*si的整数倍。
    时间轮正是利用这个关系将定时器散列到不同的链表中。

  4. 假如现在指针指向槽cs,我们要添加一个定时时间为ti的定时器,则该定时器将被插入槽ts对应的链表中:
    ts = (cs + (ti/si))%N(图11-1)

    1. 基于排序链表的定时器使用唯一的一条链表来管理所有定时器,所以插入操作的效率随着定时器数据的增多而降低。
    2. 而时间轮使用哈希表的思想,将定时器散列到不同的链表上。这样每条链表上的定时器数目都将明显少于原来的排序链表上的定时器数目,插入操作的效率基本不受定时器数目的影响。
  5. 显然,对时间轮而言,要提高定时精度,就要使si值足够小;要提高执行效率,则要求N值足够大。

时间堆

  1. 定时器的另一种思路是:
    1. 将所有定时器中超时时间最小的一个定时器的超时值作为心搏间隔。
      这样,一旦心搏函数tick被调用,超时时间最小的定时器必然到期,我们就可以在tick函数中处理该定时器。
    2. 然后,再次从剩余的定时器中找出超时时间最小的一个,并将这段最小时间设置为下一次心搏间隔。如此反复,就实现了较为准确的定时。
  2. 最小堆很适合处理这种定时方案。
    1. 最小堆是指每个节点的指都小于或等于其子节点的值的完全二叉树。

  1. 最小堆插入:
    1. 为了将一个元素X插入最小堆,我们可以在树的下一个空闲位置创建一个空穴。
    2. 如果X可以放在空穴中而不破坏堆序,则插入完成。
    3. 否则就执行上虑操作,即交互空穴和它的父节点上的元素。
    4. 不断的执行上述操作,知道X可以被放入空穴,则插入完成。

  1. 最小堆删除:
    1. 删除操作指的是删除其根节点上的元素,并且不破坏堆序性质。
    2. 执行删除操作时,需要先在根节点处创建一个空穴。由于堆现在少了一个元素,因此可以把堆的最后一个元素X移动到该堆的某个地方。
    3. 如果X可以被放入空穴,则删除操作完成。否则就执行下虑操作,即交换空穴和它的两个儿子节点中的较小者。
    4. 不断进行上述过程,知道X可以被放入空穴,则删除操作完成。

  1. 由于最小堆是一颗完全二叉树,所以可以用数组来组织其中的元素。
    1. 对于数组中的任意一个位置i上的元素,其左儿子节点在位置2i+1上,其右儿子节点在位置2i+2上,其父节点则在位置[(i-1)/2](i>0)上。
    2. 与链表来表示堆相比,用数组表示堆不仅节省空间,而且更容易实现堆的插入,删除等操作。

本文为原创文章,版权归所有,欢迎分享本文,转载请保留出处!

bingliaolong
Bingliaolong 关注:0    粉丝:0
Everything will be better.

发表评论

表情 格式 链接 私密 签到
扫一扫二维码分享