libev观察者的数据结构

时间:2012-10-22 16:31:32

标签: data-structures libev

Libev 使用三种数据结构来存储不同的观察者。

对于按时间排序的观察者,

,例如ev_timerev_periodic

关联列表,例如ev_ioev_signalev_child等。

数组,例如ev_prepareev_checkev_async等。

毫无疑问,使用堆来存储计时器观察器。但是选择链表和数组的标准是什么?

存储ev_io观察者的数据结构似乎有点复杂。它首先是一个数组,其fd作为索引,数组中的元素是ev_io watcher的链接列表。如果使用链表作为元素,则为数组分配空间更方便。是原因吗?

或者仅仅因为ev_io的插入或删除操作更频繁而且ev_prepare似乎更稳定?

还是其他任何原因?

2 个答案:

答案 0 :(得分:5)

期望是同一个fd只有少数(通常是一个,几乎总是最多两个)io观察者(类似于信号)。将列表链接放入观察器意味着不需要额外的分配,如果每个观察者使用阵列则需要。如果很多I / O观察者在同一个fd上都处于活动状态,那么这种链表方法会更慢。

使用数组是因为插入和删除非常快(观察者存储数组索引)。使用4字节索引还可以减少64位计算机上的内存需求(每个观察者12个字节,而不是双链表的16个字节),并且使用指针数组意味着所有指针在内存中彼此靠近,扫描时提高缓存效率,这对一些观察者来说是一种常见的操作。

缓存效率也是为什么在2堆上使用4堆的原因,以及将时间值复制到堆数据结构的原因,以避免在堆操作中访问观察程序内存。 / p>

儿童观察者实际上使用固定大小的哈希表,并且期望每个哈希桶的子观察者数量很少,因此列表指针成为观察者数据结构的一部分。

答案 1 :(得分:2)

原因可能是在典型情况下,需要用fd查找ev_io。底层库(epoll,select或者其他)将提供具有某些事件的fd。然后Libev会简单地将它用作索引,并且只是迭代需要调用的事件监视器的链接列表。所以它可以快速发射事件。