eventlet 和 gevent 的性能有何显着差异?
-
12-12-2019 - |
题
因此,这两个库具有相似的理念和相似的设计决策。但 这个流行的 WSGI 基准 说 eventlet
比 gevent
. 。是什么让他们的表现如此不同?
据我所知,它们之间的主要区别是:
gevent
有意依赖于并耦合到libev
(libevent
, ,之前)同时eventlet
定义独立的反应器接口并使用特定的适配器实现select
,epoll
, ,以及它后面的扭曲反应堆。 额外的反应器接口是否会对性能产生关键影响?gevent
大部分是用 Cython 编写的eventlet
是用纯Python编写的。 对于计算量不大但受 IO 限制的程序,本机编译的 Cython 是否比纯 Python 更快?的原语
gevent
模拟标准库的接口,同时eventlet
的原语与标准不同,并提供额外的层来模拟它。 额外的仿真层是否可以使eventlet
慢点?是否实施
eventlet.wsgi
只是比gevent.pywsgi
?
我真的很想知道,因为它们对我来说总体看起来非常相似。
解决方案
好吧,gevent 并不是“大部分”是用 Cython 编写的,尽管有些关键部分是用 Cython 编写的。
Cython 带来了巨大的改变。处理器优化对于编译代码效果更好。例如,分支预测在基于 VM 的系统中会崩溃,因为 VM 执行级别的分支的间接性对它来说是不透明的。缓存占用空间更小。编译后的代码在这里会产生巨大的差异,并且 IO 对延迟非常敏感。
同样,libev 也非常快。同样的原因。
eventlet 似乎不应该使用 select hub(Python 2.6 通常默认为 epoll)。不过,如果它卡在选择上,那就可以了 真的 慢(因为Python必须将select fd_set来回转换为Python列表,所以当它处于循环中间时它会变得很难看)。
我还没有做过任何分析,但我愿意打赌 libev / libevent 加上 Cython 会带来很大的不同。值得注意的是,一些线程原语位于 Cython 的 gevent 中。这是一件大事,因为很多代码通过 IO 甚至在某些地方通过标准库间接接触它们。
至于 eventlet 的附加模拟层,似乎确实有更多的弹性。在gevent中,代码路径似乎构造回调并让集线器调用它们。eventlet 似乎比 hub 在 gevent 中做更多的簿记工作。不过,我还没有对它进行简介。至于猴子补丁本身,它们看起来非常相似。
WSGI 服务器是另一个困难的服务器。值得注意的是,gevent 中的头解析被推迟到标准库,而他们自己在 eventlet 中实现它。不确定这是否会产生很大的影响,但如果其中潜伏着什么东西也就不足为奇了。最能说明问题的是,eventlet 的服务器基于标准库 BaseHTTPServer 的 Monkeypatched 版本。我无法想象这是非常理想的。Gevent 实现了一个能够感知模拟的服务器。
其他提示
抱歉回复晚了。
性能差异较大的主要原因有两个 在那个基准中:
- 如前所述,gevent 的关键路径经过大量优化
- 该基准进行压力测试。它不再受 IO 限制,因为它试图让机器运行尽可能多的请求。这就是 Cythonized 代码的闪光点。
“在现实世界中”这只发生在“slashdot”流量爆发期间。这很重要,应该做好准备,但是当这种情况发生时,您可以通过添加更多服务器或禁用资源密集型功能来做出反应。我还没有看到在负载增加时实际添加更多服务器的基准测试。
另一方面,如果基准测试会模拟“正常一天”的负载(每个网站的负载会有所不同),但通常可以近似于请求,随机暂停,重复。停顿越少,我们模拟的流量就越多。此外,基准测试的客户端必须模拟延迟。在Linux上,这可以使用awesome netem[1]来完成,否则,可以通过在recv/send调用之前放置小的延迟来完成(这将非常困难,因为基准测试通常使用更高级别的库)。
现在,如果满足这些条件,我们实际上将对 IO 限制问题进行基准测试。但结果不会太棒:所有候选者都成功服务了 10、50 甚至 200 qps 负载。无聊,对吧?因此我们可以测量延迟分布、服务 99% 请求的时间等。Gevent仍然会表现出更好的结果。但这种差异很难给人留下深刻的印象。
[1] 在 Linux 上模拟延迟和丢包