zoukankan      html  css  js  c++  java
  • 击鼓传花:对比 muduo 与 libevent2 的事件处理效率

    前面我们比较了 muduo 和 libevent2 的吞吐量,得到的结论是 muduo 比 libevent2 快 18%。有人会说,libevent2 并不是为高吞吐的应用场景而设计的,这样的比较不公平,胜之不武。为了公平起见,这回我们用 libevent2 自带的性能测试程序(击鼓传花)来对比 muduo 和 libevent2 在高并发情况下的 IO 事件处理效率。

    测试对象

    测试环境

    测试用的软硬件环境与《muduo 与 boost asio 吞吐量对比》和《muduo 与 libevent2 吞吐量对比》相同,另外我还在自己的笔记本上运行了测试,结果也附在后面。

    测试内容

    测试的场景是:有 1000 个人围成一圈,玩击鼓传花的游戏,一开始第 1 个人手里有花,他把花传给右手边的人,那个人再继续把花传给右手边的人,当花转手 100 次之后游戏停止,记录从开始到结束的时间。

    用程序表达是,有 1000 个网络连接 (socketpairs 或 pipes),数据在这些连接中顺次传递,一开始往第 1 个连接里写 1 个字节,然后从这个连接的另一头读出这 1 个字节,再写入第 2 个连接,然后读出来继续写到第 3 个连接,直到一共写了 100 次之后程序停止,记录所用的时间。

    以上是只有一个活动连接的场景,我们实际测试的是 100 个或 1000 个活动连接(即 100 朵花或 1000 朵花,均匀分散在人群手中),而连接总数(即并发数)从 100 到 100,000 (十万)。注意每个连接是两个文件描述符,为了运行测试,需要调高每个进程能打开的文件数,比如设为 256000。

    libevent2 的测试代码位于 test/bench.c,我修复了 2.0.6-rc 版里的一个小 bug,修正后的代码见 http://github.com/chenshuo/recipes/blob/master/pingpong/libevent/bench.c

    muduo 的测试代码位于 examples/pingpong/bench.cc,见 http://gist.github.com/564985#file_pingpong_bench.cc

    测试结果与讨论

    第一轮,分别用 100 个活动连接和 1000 个活动连接,无超时,读写 100 次,测试一次游戏的总时间(包含初始化)和事件处理的时间(不包含注册 event watcher)随连接数(并发数)变化的情况。具体解释见 libev 的性能测试文档 http://libev.schmorp.de/bench.html ,不同之处在于我们不比较 timer event 的性能,只比较 IO event 的性能。对每个并发数,程序循环 25 次,刨去第一次的热身数据,后 24 次算平均值。测试用的脚本在 http://github.com/chenshuo/recipes/blob/master/pingpong/libevent/run_bench.sh 。这个脚本是 libev 的作者 Marc Lehmann 写的,我略作改用,用于测试 muduo 和 libevent2。

    第一轮的结果,请先只看红线和绿线。红线是 libevent2 用的时间,绿线是 muduo 用的时间。数字越小越好。注意这个图的横坐标是对数的,每一个数量级的取值点为 1, 2, 3, 4, 5, 6, 7.5, 10。

    muduo_libevent_bench_490

    从红绿线对比可以看出:

    1. libevent2 在初始化 event watcher 上面比 muduo 快 20% (左边的两个图)

    2. 在事件处理方面(右边的两个图):a) 在 100 个活动连接的情况下,libevent2 和 muduo 分段领先。当总连接数(并发数)小于 1000 时,二者性能差不多;当总连接数大于 30000 时,muduo 略占优;当总连接数大于 1000 小于 30000 时,libevent2 明显领先。b) 在 1000 个活动连接的情况下,当并发数小于 10000 时,libevent2 和 muduo 得分接近;当并发数大于 10000 时,muduo 明显占优。

    这里我们有两个问题:1. 为什么 muduo 花在初始化上的时间比较多? 2. 为什么在一些情况下它比 libevent2 慢很多。

    我仔细分析了其中的原因,并参考了 libev 的作者 Marc Lehmann 的观点 ( http://lists.schmorp.de/pipermail/libev/2010q2/001041.html ),结论是:在第一轮初始化时,libevent2 和 muduo 都是用 epoll_ctl(fd, EPOLL_CTL_ADD, …) 来添加 fd event watcher。不同之处在于,在后面 24 轮中,muduo 使用了 epoll_ctl(fd, EPOLL_CTL_MOD, …) 来更新已有的 event watcher;然而 libevent2 继续调用 epoll_ctl(fd, EPOLL_CTL_ADD, …) 来重复添加 fd,并忽略返回的错误码 EEXIST (File exists)。在这种重复添加的情况下,EPOLL_CTL_ADD 将会快速地返回错误,而 EPOLL_CTL_MOD 会做更多的工作,花的时间也更长。于是 libevent2 捡了个便宜。

    为了验证这个结论,我改动了 muduo,让它每次都用 EPOLL_CTL_ADD 方式初始化和更新 event watcher,并忽略返回的错误。

    第二轮测试结果见上图的蓝线,可见改动之后的 muduo 的初始化性能比 libevent2 更好,事件处理的耗时也有所降低(我推测是 kernel 内部的原因)。

    这个改动只是为了验证想法,我并没有把它放到 muduo 最终的代码中去,这或许可以留作日后优化的余地。(具体的改动是 muduo/net/poller/EPollPoller.cc 第 115 行和 144 行,读者可自行验证。)

    同样的测试在双核笔记本电脑上运行了一次,结果如下:(我的笔记本的 CPU 主频是 2.4GHz,高于台式机的 1.86GHz,所以用时较少。)

    muduo_libevent_bench_6400

    结论:在事件处理效率方面,muduo 与 libevent2 总体比较接近,各擅胜场。在并发量特别大的情况下(大于 10k),muduo 略微占优。

    关于 muduo 的更多介绍请见《发布一个基于 Reactor 模式的 C++ 网络库》。muduo 的项目网站是 http://code.google.com/p/muduo ,上面有个 class diagram 可供参考。

  • 相关阅读:
    PHP实现无限极分类
    html2canvas生成并下载图片
    一次线上问题引发的过程回顾和思考,以更换两台服务器结束
    Intellij IDEA启动项目报Command line is too long. Shorten command line for XXXApplication or also for
    mq 消费消息 与发送消息传参问题
    idea 创建不了 java 文件
    Java switch 中如何使用枚举?
    Collections排序
    在idea 设置 git 的用户名
    mongodb添加字段和创建自增主键
  • 原文地址:https://www.cnblogs.com/Solstice/p/muduo_vs_libevent_bench.html
Copyright © 2011-2022 走看看