20

因此,这两个库具有相似的理念和相似的设计决策。但是这个流行的 WSGI 基准测试eventletgevent. 是什么让他们的表现如此不同?

据我所知,它们之间的主要区别是:

  • gevent有意依赖并耦合到libev( libevent, 之前的),同时eventlet定义了独立的反应器接口并使用 , 和 Twisted reactor 实现特定selectepoll适配器。额外的反应器接口是否会影响关键性能?

  • gevent主要用 Cython 编写,而eventlet用纯 Python 编写。对于计算量不大但受 IO 限制的程序,本机编译的 Cython 是否比纯 Python 更快?

  • gevent模拟标准库接口的原语,而的eventlet原语与标准不同,并提供额外的层来模拟它。额外的仿真层会eventlet变慢吗?

  • 只是执行eventlet.wsgi比差gevent.pywsgi吗?

我真的很想知道,因为它们对我来说总体上看起来很相似。

4

2 回答 2

13

好吧,gevent 不是“主要”用 Cython 编写的,尽管一些关键部分是。

Cython 有很大的不同。处理器优化在编译代码上效果更好。例如,分支预测在基于 VM 的系统中分崩离析,因为在 VM 执行级别的分支的间接性对它是不透明的。缓存占用空间更小。编译后的代码在这里有很大的不同,IO 对延迟非常敏感。

同样,libev 也非常快。同样的原因。

似乎 eventlet 不应该使用选择集线器(Python 2.6 通常默认为 epoll)。但是,如果它卡在 select 上,那将使它变得非常慢(因为 Python 必须将 select fd_set 来回转换为 Python 列表,因此当它处于循环中间时会变得很难看)。

我没有进行任何分析,但我愿意打赌 libev / libevent 加上 Cython 会产生很大的不同。值得注意的是,一些线程原语在 Cython in gevent 中。这很重要,因为很多代码通过 IO 间接接触它们,甚至在某些地方甚至是标准库。

至于 eventlet 的附加仿真层,似乎确实有更多的弹性。在 gevent 中,代码路径似乎构造了回调并让集线器调用它们。eventlet 似乎完成了集线器在 gevent 中所做的更多簿记工作。不过,我还没有对它进行分析。至于猴子补丁本身,它们看起来非常相似。

WSGI 服务器是另一个困难的服务器。值得注意的是,gevent 中的标头解析被推迟到标准库中,而他们自己在 eventlet 中实现它。不确定这是否是一个很大的影响,但如果有什么潜伏在那里也就不足为奇了。最能说明问题的是 eventlet 的服务器是基于标准库 BaseHTTPServer 的猴子补丁版本。我无法想象这是非常理想的。Gevent 实现了一个知道仿真的服务器。

于 2012-10-04T01:25:26.830 回答
1

抱歉回复晚了。

该基准的性能差异有两个主要原因:

  • 如前所述,gevent 的关键路径经过大量优化
  • 该基准进行压力测试。它不再受 IO 限制,因为它试图让机器运行尽可能多的请求。这就是 Cythonized 代码大放异彩的地方。

“在现实世界中”,仅在“斜线”流量爆发期间发生。哪一个很重要,应该准备好,但是当它发生时,您的反应是添加更多服务器或禁用资源繁重的功能。我还没有看到在负载增加时实际添加更多服务器的基准。

另一方面,如果基准测试将模拟“正常一天”的负载(从一个网站到另一个网站会有所不同),但通常可以近似为请求、随机暂停、重复。停顿越少——我们模拟的流量就越多。基准测试的客户端也必须模拟延迟。在 Linux 上,这可以使用很棒的 netem[1] 来完成,否则,通过在接收/发送调用之前放置小的延迟(这将非常困难,因为基准测试通常使用更高级别的库)。

现在,如果满足这些条件,我们实际上将基准化 IO 绑定问题。但结果不会太棒:所有候选人都成功地提供了 10、50 甚至 200 qps 的负载。无聊,对吧?所以我们可以测量延迟分布、处理 99% 请求的时间等。Gevent 仍然会显示更好的结果。但这种差异几乎不会令人印象深刻。

[1]在 Linux 上模拟延迟和丢包

于 2013-01-24T10:05:02.180 回答