libuv与libev的对比

本文发布时间: 2019-Mar-22
libuv 和 libev ,两个名字相当相近的 I/O Library ,最近有幸用两个 Library 都写了一些东西,下面就来说一说我本人对两者共同与不同点的主观表述。高性能网络编程这个话题已经被讨论烂了。异步,异步,还是异步。不管是 epoll 也好, kqueue 也罢,总是免不了异步这个话题。libev是系统异步模型的简单封装,基本上来说,它解决了 epoll,kqueuq与select 之间 API 不同的问题。保证使用 livev 的 API 编写出的程序可以在大多数 *nix 平台上运行。但是 libev 的缺点也是显而易见,由于基本只是封装了 Event Library,用起来有诸多不便。比如 accept(3) 连接以后需要手动 setnonblocking 。从 socket 读写时需要检测 EAGAIN、EWOULDBLOCK 和 EINTER 。这也是大多数人认为异步程序难写的根本原因。libuv则显得更为高层。libuv 是 joyent 给 Node 做的一套 I/O Library 。而这也导致了 libuv 最大的特点就是处处回调。基本上只要有可能阻塞的地方, libuv 都使用回调处理。这样做实际上大大减轻了程序员的工作量。因为当回调被 call 的时候, libuv 保证你有事可做,这样EAGAIN 和 EWOULDBLOCK 之类的 handle 就不是程序员的工作了, libuv 会默默的帮你搞定。libev 在 socket 发生读写事件时,只告诉你,“XX socket 可以读/写了,自己看着办吧”。往往我们需要自己申请内存并调用 read(3) 或者 write(3) 来响应 I/O 事件。libuv 则稍微复杂一些,我们分读/写两个部分来描述。当接口可读时, libuv 会调用你的 allocate callback 来申请内存并将读到的内容写入。当读取完毕后, libuv 会 call 你为这个 socket 设置的回调函数,在参数中带着这个 buffer 的信息。你只需要负责处理这个 buffer 并且 free 掉就OK了。因为是从 buffer 中读取数据,在你的 callback 被调用时数据已经 ready 了,所以程序员也就不用考虑阻塞的问题了。而对写的处理则更显巧妙。libuv 没有 write callback ,如果你想写东西,直接 generate 一个 write request 连着要写的 buffer 一起丢给 libuv , libuv 会把你的 write request 加进相应 socket 的 write queue ,在 I/O 可写时按顺序写入。C 没有闭包,所以确定读写上下文是 libuv 的使用者需要面对的问题。否则程序面对汹涌而来的 buffer 也不能分得清哪个是哪个的数据。在这一点的处理上, libuv 跟 libev 一样,都是使用了一个 void *data 来解决问题。你可以用 data 这个 member 存储任何东西,这样当 buffer 来的时候,只需要简单的把 data cast 到你需要的类型就 OK 了。libev 没有异步 DNS 解析,这一点一直广为垢病。libuv 有异步的 DNS 解析,解析结果也是通过回调的方式通知程序。libev完全是单线程的。libuv需要多线程库支持,因为其在内部维护了一个线程池来 handle 诸如 getaddrinfo(3) 这样的无法异步的调用。libev貌似是作者一个人在开发,版本管理使用的还是 CVS ,社区参与度明显不高。libuv社区十分活跃,几乎每天都有人提出 Issue 并贡献代码。libev不支持 IOCP ,如果需要在 Win 下运行的程序会很麻烦。libuv支持 IOCP ,有相应脚本编译 Win 下的库。


(以上内容不代表本站观点。)
---------------------------------
本网站以及域名有仲裁协议。
本網站以及域名有仲裁協議。

2024-Mar-04 02:11pm
栏目列表