网络库libevent、libev、libuv对比_小麒麟的成长之路-CSDN博客_libevent libuv

Libevent、libev、libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library)

异步事件库本质上是提供异步事件通知(Asynchronous Event Notification,AEN)的。异步事件通知机制就是根据发生的事件,调用相应的回调函数进行处理。

事件(Event):事件是异步事件通知机制的核心,比如fd事件、超时事件、信号事件、定时器事件。有时候也称事件为事件处理器(EventHandler),这个名称更形象,因为Handler本身表示了包含处理所需数据(或数据的地址)和处理的方法(回调函数),更像是面向对象思想中的称谓。

事件循环(EventLoop):等待并分发事件。事件循环用于管理事件。

对于应用程序来说,这些只是异步事件库提供的API,封装了异步事件库跟操作系统的交互,异步事件库会选择一种操作系统提供的机制来实现某一种事件,比如利用Unix/Linux平台的epoll机制实现网络IO事件,在同时存在多种机制可以利用时,异步事件库会采用最优机制。

对比下三个库:

libevent :名气最大,应用最广泛,历史悠久的跨平台事件库;

libev :较libevent而言,设计更简练,性能更好,但对Windows支持不够好;

libuv :开发node的过程中需要一个跨平台的事件库,他们首选了libev,但又要支持Windows,故重新封装了一套,linux下用libev实现,Windows下用IOCP实现;

libhv:https://github.com/ithewei/libhv

HW的博客_ithewei_CSDN博客-Qt,libhv,Qt5源码赏析领域博主

在github上的影响力:

可见,目前libuv的影响力最大,其次是libevent,libev关注的人较少。

优先级、事件循环、线程安全维度的对比

   特性

libevent

 libev

 libuv

  

优先级

激活的事件组织在优先级队列中,各类事

件默认的优先级是相同的,可以通过设置

事件的优先级使其优先被处理

也是通过优先级队列来管理激活的时间,

也可以设置事件优先级

没有优先级概念,按照固定的顺序访

问各类事件

事件循环    

event_base用于管理事件

激活的事件组织在优先级队列中,各类事件默认的优先级是相同的,

可以通  过设置事件的优先级   使其优先被处理

线程安全

event_base和loop都不是线程安全的,一个event_base或loop实例只能在用户的一个线程内访问(一般是主线程),注册到event_base或者loop的event都是串行访问的,即每个执行过程中,会按照优先级顺序访问已经激活的事件,执行其回调函数。所以在仅使用一个event_base或loop的情况下,回调函数的执行不存在并行关系

事件种类

type

libevent

libev

libuv

IO

fd

io

fs_event

计时器(mono clock

timer

timer

timter

计时器(wall clock

--

periodic

--

信号

signal

signal

signal

进程控制

--

child

process

文件stat

--

stat

fs_poll

每次循环都会执行的Idle事件

--

idle

idle

循环block之前执行

--

prepare

prepare

循环blcck之后执行

--

check

check

嵌套loop

--

embed

--

fork

--

fork

--

loop销毁之前的清理工作

--

cleanup

--

操作另一个线程中的loop

--

async

async

stream ( tcp, pipe, tty )

stream ( tcp, pipe, tty )

stream ( tcp, pipe, tty )

stream ( tcp, pipe, tty )

这个对比对于libev和libuv更有意义,对于libevent,很多都是跟其设计思想有关的。 libev中的embed很少用,libuv没有也没关系;cleanup完全可以用libuv中的async_exit来替代;libuv没有fork事件。

可移植性

三个库都支持Linux, *BSD, Mac OS X, Solaris, Windows

type

libevent

libev

libuv

dev/poll (Solaris)

y

y

y

event ports

y

y

y

kqueue (*BSD)

y

y

y

POSIX select

y

y

y

Windows select

y

y

y

Windows IOCP

y

N

y

poll

y

y

y

epoll

y

y

y

对于Unix/Linux平台,没有什么大不同,优先选择epoll,对于windows,libevent、libev都使用select检测和分发事件(不I/O),libuv在windows下使用IOCP。libevent有一个socket handle, 在windows上使用IOCP进行读写。libev没有类似的。但是libevent的IOCP支持也不是很好(性能不高)。所以如果是在windows平台下,使用原生的IOCP进行I/O,或者使用libuv。

异步架构程序设计原则

1、回调函数不可以执行过长时间,因为一个loop中可能包含其他事件,尤其是会影响一些准确度要求比较高的timer。

2、尽量采用库中所缓存的时间,有时候需要根据时间差来执行timeout之类的操作。当然能够利用库中的timer最好。

参考:http://zheolong.github.io/blog/libevent-libev-libuv/

https://cpp.libhunt.com/

libevent

libev

libuv

node.js

工具库和框架之间的区别,asio是被设计成一套工具库而不是框架。

什么是框架? 框架就是一套固定了编程结构的库,任何用户使用它,必须按照框架库的结构设计自己的应用,比如MFC中的OnOK, OnXXX之类,又或者ACE中的ACE_Handler::handle_xxx_yyy之类,用户通过在这些派生类的虚函数中实现自己需要的处理。

什么是工具库? 而工具库就是一套api,而不是框架,用户使用它,无需从指定的地方去填写代码。程序的框架由用户自己决定。类似的库有C++中的STL,C中的标准库,它们从来不提供编程框架,而只提供工具函数,让用户通过这些工具函数,正确的组织自己的程序结构。

框架的限制非常多,不够灵活

https://www.avboost.com/t/topic/654

select

select 实在是太慢了.

在这种背景下, IBM 老大哥带领着MS老弟先搞了 IOCP . 然而开源的人有开源的做法, 在 NIH 综合症的影响下, BSD 的人敢为天下所不齿, 发明了 Kqueue. 同样在 NIH 综合症影响下, Linux 的一群 M* 的猴子捣鼓出了 epoll.

分裂, 让人头疼.

于是程序员们急需一个上天入地无所不能的法宝的法宝, 把这3家法宝给统御起来.率先站出来悳瑟的是 ACE.

ACE 过于复杂,甚至比它试图封装的对象更复杂

libevent 就如名字所言,是一个异步事件框架。

libevent把简单问题简单化,让异步网络编程反朴归真,应该来说,本是一个好库。

然而 libevent 因为设计缺陷,例如使用全局变量,定时器无法处理时间跳变,诸如此类的设计缺陷导致了 libev 的出现。
libev 就是为了克服libevent的缺陷而诞生的。然而,libev 就一定好了吗?

libev 带着对 libevent 的怨气出世了。

编写异步程序, 最需要的2个抽象能力, 其一为协程,其二是函数对象,包括匿名函数对象, 也就是lambda。
C统统没有。函数对象是实现闭包比不可少的,如果没有函数对象, 就只能通过携带 void* 指针的形式迂回完整,繁琐不说,还特别容易出错。

尽管C 有那么多缺点,然而 libev 还未来得及被C的缺点拖累,因为他不支持 IOCP. 于是 libuv 就出来给 libev 擦屁股了。

libuv 可以说是 C 语言的异步库所能达到的最高高度了。完完全全的触碰到了C语言的自身瓶颈,好在libuv 只是 nodejs 的底层库,上层软件转移到 javascript 语言而逃避了 C 的禁锢。

ASIO 腾空出世

在地球最大的岛上,另一位少年开始拜读 ACE 的大作。那时候,没有 libuv 没有 libev 更没有 libevent . 有的只是 ACE.

少年在一次开发者大会的演讲上,再次透露,网络库不宜做成框架,而是要像系统的API那样,作为一个乐高积木。ACE 做成了一个框架,同样不妥。

buffers

有了闭包的支持,内存管理也变得轻轻松松起来。
ASIO 本身并不管理内存,所有的IO操作,只提交对用户管理的内存的引用,称 Buffers。asio::buffers 引用了用户提交的内存,保持整个 IO 期间,这块内存的有效性是用户的责任。然而这并不难!
因为回调是一个闭包。通过闭包持有内存,只要 asio 还未回调,闭包就在,闭包在,内存在。asio 在调用完回调后才删除相应的闭包。因此资源管理的责任可以丢给闭包,而闭包可以通过智能指针精确的控制内存。
不是 GC , 胜于 GC 千百倍!益于c++的 RAII机制,再无内存泄漏之忧!

asio采用proactor模式,而windows下的IOCP本身就是这个模式的体现

在高性能服务器并发模型设计中,Reactor和Proactor是两个经常用到的设计模式,前者用于同步IO,后者用于异步IO,前者在IO操作 就绪的情况下通知用户,用户再采取实际的IO操作,后者是在IO操作完成后通知用户。

IOCP的设计就是Proactor 模式的完美体现,而epoll则很容易实现Reactor模式,asio设计为跨平台,并且在linux下采用epoll,我的印象中linux对异步 IO的支持没有windows那么完善(看看IOCP和epoll模型的区别就知道),那么asio是怎么用epoll机制实现proactor模式的 呢,刚开始想的是应该在应用层做了一层封装,就是asio内部应该有某个循环调用epoll_wait,当有IO事件就绪时帮用户做一些操作(比如把数据 拷贝到我们提交的缓冲区),然后在操作完成的时候调用我们的handler(后来看代码基本是这样).OK,不说废话了.

本质上来讲libevent应该是同步的因为如果看到底层封装的select和epoll就会发现,里面仍然是个while循环,在不停的询问,是否准备就绪,
而异步同步IO的主要区别就是,应用发起一个 IO 操作以后,不等待内核 IO 操作的完成,等内核完成 IO 操作以后会通知应用程序,这其实就是同步和异步最关键的区别,同步必须等待或者主动的去询问 IO 是否完成,显然select和epoll是同步的。
另外本身Reactor模式就是同步的模式不是吗?

如果你理解底层的select或者epoll。你会发现它其实是同步的。有一个while循环,等待事件触发条件。满足条件则调用相应的callback函数。因此本质上还是同步的。不过长了一个异步的脸

libevent本身是一个Reactor,是同步的。但libevent的bufferevent是用Reactor实现了一个Proactor,所以libevent又是异步的

libuv 和 libev ,两个名字相当相近的 I/O Library,最近有幸用两个 Library 都写了一些东西,下面就来说一说我本人对两者共同与不同点的主观表述。

高性能网络编程这个话题已经被讨论烂了。异步,异步,还是异步。不管是 epoll 也好,kqueue 也罢,总是免不了异步这个话题。

libuv是异步的,libev是同步的多路IO复用。

libev 是系统I/O复用的简单封装,基本上来说,它解决了 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 下的库。

-----------------------------------------------------------------------------------

Q: 博主有没做过两者的benchmark,他们之前的性能对比如何?

A: 当时用 libev 和 libuv 写过一个简单的 HTTP Hello World Server 。具体结果记不清楚了但是可以说性能差距在 5% 以内。

Q:  libuv 在 unix 上应该是用 libev 作为 non-blocking IO 的实现的吧?libuv 中线程池里线程的数量会增加么,是否会有上限?如果上限到了是不是就会出现 block 的情况?

A: 1. libuv 在大概5个月前已经完全不使用 libev 了,参见 commit665a316aa9d551ffdd00d1192d0c3d9c88d7e866 ; 2. libuv 的线程池在BSS上,数量固定为4个,参见:https://github.com/joyent/libuv/blob/master/src/unix/threadpool.c#L28 ; 3. libuv 的线程池共享一个work queue ,所以不会出现 block 的情况

libevent : 名气最大,应用最广泛,历史悠久的跨平台事件库;
libev : 较libevent而言,设计更简练,性能更好,但对Windows支持不够好;
libuv : 开发node的过程中需要一个跨平台的事件库,他们首选了libev,但又要支持Windows,故重新封装了一套,*nix下用libev实现,Windows下用IOCP实现;

网络库libevent、libev、libuv、libhv对比相关推荐

  1. 网络库libevent、libev、libuv对比

    Libevent.libev.libuv三个网络库,都是c语言实现的异步事件库Asynchronousevent library). 异步事件库本质上是提供异步事件通知(Asynchronous Ev ...

  2. 偷懒的网络框架libevent、libev框架介绍

    libevent.libev框架介绍 前言 概述 libevent 编译安装libevent libevent的封装层次 IO事件检测的封装与api介绍 事件管理器event_base `构建事件管理 ...

  3. 国产网络库libhv开源四周年回顾

    libhv是一个跨平台的c/c++网络库,本文写在libhv开源四周年之际,借机回顾了libhv的发展历程. github地址:https://github.com/ithewei/libhv 文章目 ...

  4. 详解libevent网络库(一)---框架的搭建

    使用libevent实现进程间通讯 libevent概述 起源 获取源码 初识libevent 框架学习-- event_base 重中之重 从思想上出发 一:掏出火箭壳 --->event_b ...

  5. libuv 网络库设计概览译

    设计概览 libuv 是一种支持跨平台的网络库,最初是为了NodeJS作为某个模块实现的,主要基于事件驱动的I/O 模型设计的. 这个库不仅仅对不同的I/O polling 机制提供简单的抽象. ha ...

  6. C++后端开发程序员应该彻底搞懂的【libevent网络库】,libevent组件构成以及编程要领丨Linux服务器开发丨服务端编程

    90分钟搞懂libevent网络库 1. 服务端事件组成 2. libevent组件构成以及编程概要 3. memcached是如何使用libevent 视频讲解如下,点击观看: C++后端开发程序员 ...

  7. 详解Libevent网络库

    项目中要用到libevent,所以就自学了libevent,参考资料为张亮的<libevent源码深度剖析>和<linux高性能服务器编程> Libevent简介 Libeve ...

  8. ASIO 腾空出世 (那些年我们追过的网络库.PartII)

    ASIO 腾空出世 在地球最大的岛上,另一位少年开始拜读 ACE 的大作.那时候,没有 libuv 没有 libev 更没有 libevent . 有的只是 ACE. 然而这个南方小国的少年没有跟风陷 ...

  9. 那些年我们追过的网络库(PartI)

    为什么要用 C++ 编写服务端程序? 如果说答案是性能,那么肯定有人会满不在乎.觉得性能不够的话, 只要加机器就可以了. 然而更少的机器,意味着更低的能耗,更少的硬件投入,更少的人力资源投入去维护机器 ...

最新文章

  1. Docker学习(七)-----Docker安装nginx
  2. jsp error-page没有生效
  3. 在微服务架构下基于 Prometheus 构建一体化监控平台的最佳实践
  4. win7怎么跳过硬盘自检_win10系统改装win7步骤教程
  5. 固态铝电解电容与液态铝电解电容
  6. 金蝶CLOUD星空云tempdb过大处理方法
  7. C#读书笔记:线程,任务和同步
  8. python练习,随机数字 函数,循环,if,格式化输出
  9. 【转】D365 FO第三方访问https证书问题
  10. php : 常用函数
  11. 信息学奥赛C++语言:斐波那契第n项
  12. this--学习笔记
  13. 科技抗疫,少年可期,为这群有AI的天使开发者疯狂打call
  14. 航空航天工程用不用学c语言,2020年北京航空航天软件工程991答疑
  15. web前端工程师岗位职责、岗位要求
  16. Android无线调试设备WIFI安装apk
  17. 遇到网站被黑,怎么解决?
  18. macOS 13 Ventura系统自动开机在哪设置?
  19. PHP小V脸蛋白线,HPH小v脸蛋白线好不好用?HPH小v脸蛋白线怎么用
  20. Contrastive Learning Based on Transformer for Hyperspectral Image Classification

热门文章

  1. python下载图片插入excel_Python向Excel中插入图片的简单实现方法
  2. FI和MM集成自动记账-采购收货发票校验业务-OBYC
  3. HTML基础选择器之属性选择器的基本介绍
  4. 日常开发CSS小技巧整理
  5. 前缀、中缀、后缀表达式
  6. 股票投资 策略(收集)
  7. C++11新特性之long long类型
  8. 软件工程Alpha冲刺day7
  9. unity-shader-ShaderGraph可视化shader
  10. Android音频子系统(十)------MTK Audio录音流程代码解析