当前位置:首页 > 技术学院 > 技术前线
[导读]服务器编程中一块是定时器,影响着服务器性能 定时器一个作用是用于定时检测客户端连接,并踢掉非活动连接; 定时器一般会把定时事件封装成定时器,并进行组织以方便管理

计时

在linux中,一般由文件下的alarm函数和setitimer来设置定时器,到时间则发出SIGALARM,并调用指定的到期信号处理函数,

signal(SIGALRM, handler);函数来设置到期事件处理函数,而这个到期事件处理函数在游双的书例子里可以看到,是定时器类里的tick函数,即每隔一个周期调用tick()一次,注意要区分timer到期的回调函数和SIGALARM的回调函数

封装timer

在服务器编程里,要处理定时事件,会封装个定时器timer类,其中一般会包含到期时间和回调函数,如muduo中timer.h的实现,和l游双书中的定时器那一章的种种例子,并根据不同实现方式增加额外的数据如链表的节点

而定时器应该给出的用户接口有注册定时器,注销定时器;注册定时器应增加区分重复定时器和一次性定时器

还应该给出定期触发的函数,即上面提到的tick(),在tick函数里判断timer里哪些是已经过期的,触发定时事件,根据定时器是否是重复的删除或者重新设置此定时器

定时器实现类型

定时器会用到什么操作呢?它的插入,指定注销,注销到期的定时器,根据这几点看一下如何设计定时器,ps.注意区分指定注销和注销到期,因为以下的实现大多是已经排序好的,注销到期的一般是从头开始往下找,而指定注销是注销当中某个节点的定时器

先说明libevent中的实现是最小堆,muduo是采用了红黑树来实现,以下列出几种类型的定时器实现

最简单的实现:双向链表

直接利用链表实现,每一个定时器作为一个链表的节点,这样做最直观,而几种操作的复杂度是:

添加的时候就直接插入到链表末端,时间复杂度O(1)

找到到期timer,则需要遍历全部,时间复杂度为O(n)

代码请看参考资料[1]

优化的链表:排序双向链表

优化操作:每次插入按到期时间进行排序,时间复杂度是:

插入为O(n),找到到期timer时间复杂度是O(1)的操作,指定timer删除操作,是O(1)的复杂度,这也是为什么要用双向链表的原因,直接传入一个链表节点进行删除,,ps:这里排序链表判断到期虽然会有个while循环,是为了找到地一个非过期并执行前面过期的所有回调函数,平均下来还是个O(1)的操作

代码:参考资料[1]

最小堆实现

优化点:最小堆的插入操作是log(n),参考下堆的插入操作:插入到堆最后面以后,进行上浮调整,最大调整次数为树的高度,即log(n),

到期触发的时间复杂度为O(1),及取最值,而堆这个结构最适合做这个,在游双的书中能看到,最小堆的实现alarm信号发送的时间设置成堆中最近的触发时间,每次取完后其实还有个log(n)的heapify调整时间,估计参考资料[1]和游双都把这个操作延后到平时(即延迟销毁,游双的书第11章第215页)了,

,指定删除操作则略微麻烦,这也是为什么muduo不采用这个方法的原因

(如果del_timer函数的参数,传入timer作参数直接删除再堆化一下就行,如果传入参数为定时器序号,则遍历到再删除为O(n),用一个map来存序号到定时器在堆中位置,则为时间O(1))(但是每次变换都)

代码:参考资料[1]或者游双的书

红黑树实现

muduo的实现,顺便提下,heap比起红黑树的好处是,像陈硕书中说的:内存的局部性更好,参考资料[1]说的内存使用率更好,且性能会相差一点,

红黑树对比堆查找特定的timer速度会快一点(参考[1]说的)

有时间复杂度就不分析了,muduo书中还提到了了一下set,map,multiset,multimap的选择

代码:参考muduo(直接用了现成的数据结构)或者参考资料[1]或者游双的书

时间轮

时间轮的介绍先略过TODO在游双的书中和陈硕的书中示例代码部分都有提到,

前文没有分清定时器的概念,晚点再改TODO

首先要把socket fd和定时器的指针加以封装,以便删除使用,即可以通过这个类来访问fd和timer*,要删除时间轮中的某个fd对应的timer*我们直接访问这个数据结构,在游双的书里取名为client_data

封装timer类,包括时间,到期执行的回调函数,这个类是以便时间轮使用,在时间轮中,我们是直接用timer*来排序使用的,

分析下各种操作的时间复杂度

插入:直接调用API传入timer*,而时间轮里每个轮里的是链表,链表删除直接O(1)

添加:插入操作是对时间进行取模放入那个槽中,时间复杂度也是O(1)

删除:直接传入timer*,O(1)

到期触发:是n个定时器,p个槽,根据哈希函数不同值均匀分布的特点,大概时间复杂度是O(n/p),游双的书中称之为:比O(n)好很多

使用IO复用

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

Holtek新推出BS67F2432具备触控按键、高精准度HIRC与LCD驱动器Flash MCU。主要特色为内建高精准度4MHz HIRC振荡电路、8路触控按键及最大支持4COM×15SEG LCD驱动器。适用于触控接...

关键字: MCU LCD驱动器 定时器

Holtek持续扩展Touch A/D Flash MCU产品,新增系列成员BS86C12CA,延续优良抗干扰特性,提供丰富的定时器资源并支持LXT振荡器。引脚与BS86C08C及BS86D12C相容,具高性价比,适合需...

关键字: MCU LXT振荡器 定时器

采用MCU(微控制器单元)模块实现定时器的设计是通过利用MCU内部的定时器/计数器资源来实现的。定时器是MCU中的一个重要功能模块,它可以在特定的时间间隔内执行特定的操作,如产生中断、更新定时器值、触发其他设备等。

关键字: mcu模块 定时器

单片机的外设是指与单片机核心处理部分相连的附加硬件模块,它们能够扩展单片机的功能和能力。这些外设包括各种模块和接口,用于处理特定的任务或实现特定的功能。

关键字: 单片机 定时器

PIC单片机是基于RISC系统结构的单片机,最初的设计是支持PDP(编程数据处理器)计算机。大量的操作可以用来控制外围设备。PIC单片机比微控制器具有更快的程序执行能力。它是由微芯片技术公司于1889年发明的,是一种8位...

关键字: PIC单片机 定时器 中断

外部输入、输出继电器、内部继电器、定时器、计数器等器件的接点可多次重复使用,无需用复杂的程序结构来减少接点的使用次数。

关键字: plc编程 定时器 计数器

单片机可以通过“定时/计数模式选择位C/T”令定时/计数器工作于定时或计数模式下,也可通过“工作方式选择位M1M0”设定其工作方式。C/T和M1M0等与定时/计数器有关的位在寄存器TCON或TMOD中,见表4-8和表4-...

关键字: 寄存器 计数器 定时器

在家电产品和工业应用系统中,定时和计数是两种常用的功能,如:微波炉加热计时和流水线上产品数目统计等。MCS-51单片机内部集成的两个可编程定时/计数器T0和T1使用灵活、方便,在仪器仪表等工业产品中应用广泛。

关键字: 计数器 定时器 单片机

TMOD 的地址是 89H ,它不能位寻址 ,它里面的内容被称为方式字,设置时一次写入,其各位的定义如图 6.2 所示。高 4 位用于定时器 T1 ,低 4 位用于定时器 T0 。

关键字: 定时器 计数器 单片机

单片机定时器其实跟我们平时常说的计数器,是同一个电子元件,只不过计数器记录的是单片机外部情况,所接收的也是外部脉冲,而定时器则是由单片机自身提供的一个非常稳定的计数器,这个稳定的计数器就是单片机上连接的晶振部件。

关键字: 定时器 计数器 单片机
关闭
关闭