轮询算法中效率和延迟的均衡

来源:互联网 发布:传奇世界翅膀升级数据 编辑:程序博客网 时间:2024/06/15 00:21

    所谓的轮询算法是对事件的一种检测机制,如I/O设备的状态改变等。常见的事件检测机制有轮询,中断,DMA,通道等,其中轮询和中断是事件通知的两种基本方式,DMA和通道都是一种数据传输方式。能用中断的情况下当然尽量用中断,Windows中基于中断的I/O模型有好几种,如Select模型,异步模型等等。但是中断需要硬件支持,很多情况下轮询还是不可避免的,如两个进程通过共享内存通信,共享内存只是一块内存,并不支持中断模式,因此需要通过轮询工作。
    轮询和中断相比的一个重要问题就是效率。中断模式下事件的发生会由事件源自动通知CPU,而轮询模式下你不知道什么时候事件发生,因此就需要不断的检测事件是否发生,而对于发生频率不高的事件大部分检测都是无效的,这样也就浪费了大量的CPU时间。为了提高效率,一般选择每隔一段时间检测一次事件是否发生。
    但是这样不可避免的增加了事件的处理延迟。延迟的最大值等于检测周期的最大值。为此需要在效率和延迟之间进行均衡。延迟分为平均延迟和突发延迟,对于平均延迟的提高,必然会伤害到效率,它和效率之间存在简单的线性关系,此消彼长,为了在不伤害效率的情况下减少延迟,需要根据CPU的处理能力来选择合适的检测周期。
    对于突发延迟,它和效率之间没有必然的联系,和算法有着很重要的关系。也就是说好的算法可以在不损害效率的情况下大大减少突发延迟。突发延迟是指某一段时间内事件的发生速率明显高于时间发生的平均速率,对于这段时间内事件的平均延迟称为突发延迟。对于突发延迟的减少一般根据局部性原则进行算法设计。
    一种简单的处理方式是,只要检测到事件的发生就连续检测,直到检测不到事件的发生时才休眠一段时间。这种算法虽然简单但是对于突发延迟的减少是很明显的,缺点也很明显,对于那些周期事件的检测效率较低。这种算法不仅能够减少突发延迟,还可以将并行事件转换为串行事件,Linux的中断响应就采取了这种方式将并行事件转换成了串行事件,避免了中断的重入。其原理是基本一致的。
    更好一点的处理方式会引入反馈,根据当前收集到的信息对休眠时间进行动态调整,这一般对于发生频率很低,偶然性较大的事件检测有很大的好处。对检测周期设定一个初始值,然后根据事件检测结果和当前检测周期来动态调整下一次的检测周期。如果时间检测失败,则增大检测周期,直到最大阈值;如果时间检测成功则立即将检测周期设为最小阈值。这样就实现了"快速收敛"。对于初始检测周期的设置也是很讲究的,如果比较靠近最小阈值则是"快启动",靠近最大阈值则是"慢启动"。TCP协议对于数据包的检测采用的就是类似的算法。上述的简单处理方式也是这种算法的特例。
    综上,效率和延迟本是一对矛盾体。然而往往对用户产生影响的不是平均延迟,而是突发延迟。如果你的程序出现了明显的用户可以感受到的延迟时,首先考虑的就应该是对突发延迟的处理是否合适,其次才是平均延迟。平均延迟的提高对效率的影响是很大的,所以提高的空间也就很小,但是突发延迟则不然。

原创粉丝点击