libevent源码学习(12):超时管理之common_timeout

目录

前言

common_timeout的作用

common_timeout的结构定义

common_timeout与一般timeout的区分

获取common_timeout在common_timeout_queues中的下标

判断一个timeval是否为common_timeout

判断两个timeval是否是同样的common_timeout

获取common_timeout对应的common_timeout_list

创建一个common_timeout

为event添加common_timeout

从common_timeout_list到min_heap

激活common_timeout对应的event

总结


以下源码均基于libevent-2.0.21-stable。

前言

       用于超时管理的min_heap,在执行主循环的过程中,它每次都会去检查min_heap的堆顶event是否超时,如果超时的话就进行相应的处理并且从min_heap中移除这个event,然后调整整个堆,直到堆顶event未超时则停止检查。这种方法虽然好,逻辑清晰,看上去每次删除堆顶超时的event时间复杂度只需要O(logn),效率也足够高,但是如果某次主循环中超时的event过多,假设有m个event超时了需要同时处理,那么此时需要花费的时间就是O(mlogn),当m足够多的时候,这个效率还是比较低的,因此就引入了common_timeout这一结构。

       那么它的作用是什么呢?

common_timeout的作用

       简单来说,common_timeout把base中所有拥有共同点的event放在了一起,而这个所谓的“共同点”就是指超时时长相同,这些超时时长相同的event,他们的超时时间是不同的。

       举个例子,我添加了一个eventA,设置它的超时时长为5分钟,即如果5分钟内没有触发相应事件,那么5分钟后就直接进行回调处理;然后我再添加了一个eventB,也设置它的超时时长为5分钟。那么就称eventA和eventB具有相同的超时时长。如果eventA添加的时间为10:00,eventB添加的时间为11:00,那么二者的超时时间就一个是10:05,另一个就是11:05,因此超时时长相同,但是超时时间是不同的。

       拥有相同超时时长的所有event构成一个链表events,并且让它们按照超时时间的先后按升序排列(即相同超时时长中最先超时的那个event放在最前面),而events中设置一个内部使用的timeout_event作为代表,把最先超时的那个event的超时时间添加到timeout_event中,然后把timeout_event放到min_heap中,当放到min_heap中的timeout_event超时,就回到events中,从前往后把所有超时的event全部激活。下面来分析这种情况下的时间复杂度。

       在这种情况下,相当于每一个由相同超时时长的event组成的链表都在min_heap中存在一个“代表”,因此如果有t个链表的“代表”在min_heap中超时,那么处理这个"代表"后调整堆花费的时间就是O(tlogn),如果一共有m个event超时了,相当于所有链表加起来需要遍历m个event,因此common_timeout在处理m个event超时的时间复杂度就是O(tlogn+m),由此也能看出来使用common_timeout+min_heap和只使用min_heap的差别了:如果t远小于m,相当于超时的event分布的链表比较集中,那么前者的效率更高,这种优势当n越大时越明显;如果t和m相近,相当于超时的event分布在不同的链表,此时还是后者效率更高。

       因此到底是否使用common_timeout,还是视情况而定,这也是为什么在libevent中虽然设计了common_timeout,但是并没有将其直接用来管理超时,而是留给用户接口去选择是否使用common_timeout,可见,common_timeout+min_heap的超时管理并非就一定比只使用min_heap的效率高。而至于具体在什么情况下使用哪种方式,个人觉得如果超时的event很多那还是应该考虑使用common_timeout+min_heap,因为event很多的话分布的链表也更大概率密集一些;如果超时的event比较少的话,还是应该只使用min_heap。

common_timeout的结构定义

       在event_base的结构体中,含有以下定义:

struct event_base
{
    ......

    /** An array of common_timeout_list* for all of the common timeout
	 * values we know. */
	struct common_timeout_list **common_timeout_queues;   //common_timeout_list *数组,存放不同超时时长的common_timeout_list的指针
	/** The number of entries used in common_timeout_queues */
	int n_common_timeouts;  //common_timeout_queues中实
  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Libevent是一个事件驱动的网络编程框架,而event.h是其核心头文件之一。该头文件定义了事件处理相关的结构体、函数和宏等内容。 下面是event.h中常用的一些定义和函数: ### 1.事件回调函数 ```c typedef void (*event_callback_fn)(evutil_socket_t fd, short events, void *arg); ``` 该类型定义了事件回调函数的原型,其中fd是事件所在的文件描述符,events是事件类型,arg是用户传入的参数。 ### 2.事件结构体 ```c struct event { event_callback_fn ev_callback; // 事件回调函数 int ev_fd; // 事件所在的文件描述符 short ev_events; // 事件类型 short ev_res; // 事件结果 struct event_base *ev_base; // 事件所属的event_base void *ev_arg; // 用户传入的参数 }; ``` 该结构体表示一个事件,其中ev_callback是事件回调函数,ev_fd是事件所在的文件描述符,ev_events是事件类型,ev_res是事件结果,ev_base是事件所属的event_base,ev_arg是用户传入的参数。 ### 3.事件类型 ```c #define EV_TIMEOUT 0x01 #define EV_READ 0x02 #define EV_WRITE 0x04 #define EV_SIGNAL 0x08 #define EV_PERSIST 0x10 #define EV_ET 0x20 ``` 该宏定义了事件类型,分别为超时事件、读事件、写事件、信号事件、持续事件和边缘触发事件。 ### 4.事件处理函数 ```c struct event_base *event_base_new(void); int event_base_dispatch(struct event_base *base); int event_base_loopexit(struct event_base *base, const struct timeval *tv); void event_base_free(struct event_base *base); ``` 这些函数用于创建event_base、处理事件、退出事件循环和释放event_base等操作。 以上是event.h中的一些常用内容,更多细节可以查看源码和官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值