什么使eventlet和gevent之间的性能有显着差异?

时间:2012-10-01 08:41:50

标签: performance wsgi asyncsocket gevent eventlet

这两个库共享相似的哲学和类似的设计决策。但是this popular WSGI benchmarkeventletgevent慢。是什么让他们的表现如此不同?

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

  • gevent故意依赖于libevlibevent,之前),而eventlet定义独立的反应器接口,并使用{{1}实现特定的适配器它后面是{},select和扭曲的反应堆。 额外的反应器接口是否会产生关键的性能命中?

  • epoll主要是用Cython编写的,而gevent是用纯Python编写的。 原生编译的Cython是否比纯Python更快,对于计算量不大但是IO绑定的程序?

  • eventlet的基元模拟标准库的接口,而gevent的基元与标准不同,并提供额外的层来模拟它。 其他仿真层是否会使eventlet变慢?

  • eventlet的实施是否比eventlet.wsgi差?

我真的很好奇,因为它们对我来说整体看起来很相似。

2 个答案:

答案 0 :(得分:12)

好吧,gevent不是“大部分”用Cython编写的,虽然有些关键部分是。

Cython带来了巨大的变化。使用编译代码可以更好地处理器优化。例如,分支预测在基于VM的系统中崩溃,因为VM执行级别的分支的间接对它是不透明的。缓存占用空间更小。编译代码在这里产生了巨大的差异,IO可能对延迟非常敏感。

以类似的方式,libev非常快。原因相同。

似乎eventlet不应该使用select hub(Python 2.6通常默认为epoll)。如果它被卡在选择上,那会使它真的慢(因为Python必须将select fd_set来回转换为Python列表,所以当它在一个中间时会变得很难看循环)。

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

至于eventlet的附加仿真层,似乎确实有更多的弹性。在gevent中,代码路径似乎构造了回调并让集线器调用它们。 eventlet似乎做了更多的集线器在gevent中进行的簿记。尽管如此,我还没有对它进行分析。至于monkeypatching本身,它们看起来非常相似。

WSGI服务器是另一个困难的服务器。值得注意的是,gevent中的头解析被推迟到标准库,而他们自己在eventlet中实现它。不确定这是否会产生重大影响,但如果有潜伏的东西就不足为奇了。最有说服力的是,eventlet的服务器基于标准库BaseHTTPServer的monkeypatched版本。我无法想象这是非常理想的。 Gevent实现了一个知道仿真的服务器。

答案 1 :(得分:1)

很抱歉迟到的回复。

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

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

“在现实世界中”只发生在“slashdot”爆发的交通中。哪个是重要的,应该做好准备,但是当它发生时,您会通过添加更多服务器或禁用资源繁重的功能来做出反应。我没有看到在负载增加时实际添加更多服务器的基准测试。

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

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

[1] Simulate delayed and dropped packets on Linux