就设计理念而言,libev 的创建是为了改进 libevent 中的一些架构决策,例如,全局变量的使用使得在多线程环境中难以安全地使用 libevent,watcher 结构很大,因为它们结合了 I/O,时间和信号处理程序合二为一,额外的组件(例如 http 和 dns 服务器)的实现质量不佳并导致安全问题,而且计时器不精确,无法很好地应对时间跳跃。
Libev 尝试通过不使用全局变量而是对所有函数使用循环上下文,通过对每种事件类型使用小型观察程序来改进其中的每一个(I/O 观察程序在 x86_64 上使用 56 个字节,而在 libevent 上使用 136 个字节) ,允许额外的事件类型,例如基于挂钟与单调时间的计时器、线程间中断、准备和检查观察者以嵌入其他事件循环或被嵌入等等。
额外的组件问题通过根本没有它们来“解决”,因此 libev 可以小而高效,但您还需要在其他地方寻找 http 库,因为 libev 根本没有(例如,有一个非常相关的库叫libeio,它做异步I/O,可以单独使用,也可以和libev一起使用,所以可以混搭。
因此,简而言之,libev 只尝试做一件事(POSIX 事件库),并且以最有效的方式进行。 Libevent 试图为您提供完整的解决方案(事件库、非阻塞 I/O 库、http 服务器、DNS 客户端)。
或者,更短一点,libev 试图遵循 UNIX 工具箱的理念,即只做一件事,尽可能好。
请注意,这是设计理念,我可以权威地声明,因为我设计了 libev。这些设计目标是否真的达到了,或者理念是否基于合理的原则,由你来判断。
2017 年更新:
我被多次询问我指的是什么计时器不精确,以及为什么 libev 不支持 Windows 上的 IOCP。
至于定时器,libevent 会在你不知道的情况下,相对于某个未知的未来基准时间来安排定时器。 Libev 可以提前告诉您它将使用什么基准时间来安排计时器,这允许程序同时使用 libevent 方法和 libev 方法。此外,libevent 有时会提前过期计时器,具体取决于后端。前者是 API 问题,后者是可修复的(可能已经修复了 - 我没有检查)。
至于 IOCP 支持 - 我认为无法做到,因为 IOCP 根本不够强大。一方面,他们需要一种特殊的套接字类型,这将进一步限制 Windows 上允许的句柄集(例如,perl 使用的套接字是 IOCP 的“错误”类型)。此外,IOCP 根本不支持 I/O 就绪事件,它们只能执行实际的 I/O。有一些句柄类型的变通方法,例如进行虚拟 0 字节读取,但同样,这会限制您可以在 Windows 上使用的句柄类型,而且会依赖可能未由所有套接字提供程序共享的未记录行为.
据我所知,没有其他事件库支持 Windows 上的 IOCP。 libevent 所做的是,除了事件库之外,它还允许您将读/写操作排队,然后可以通过 IOCP 完成。由于 libev 不为您执行 I/O,因此无法在 libev 本身中使用 IOCP。
这确实是设计使然——libev 试图做到小而类似于 POSIX,而 windows 根本没有一种有效的方法来获取 POSIX 样式的 I/O 事件。如果 IOCP 很重要,您要么必须自己使用它们,要么确实使用为您执行 I/O 的许多其他框架中的一些,因此可以使用 IOCP。