这两个库共享相似的哲学和类似的设计决策。但是this popular WSGI benchmark说eventlet
比gevent
慢。是什么让他们的表现如此不同?
据我所知,他们之间的主要区别是:
gevent
故意依赖于libev
(libevent
,之前),而eventlet
定义独立的反应器接口,并使用{{1}实现特定的适配器它后面是{},select
和扭曲的反应堆。 额外的反应器接口是否会产生关键的性能命中?
epoll
主要是用Cython编写的,而gevent
是用纯Python编写的。 原生编译的Cython是否比纯Python更快,对于计算量不大但是IO绑定的程序?
eventlet
的基元模拟标准库的接口,而gevent
的基元与标准不同,并提供额外的层来模拟它。 其他仿真层是否会使eventlet
变慢?
eventlet
的实施是否比eventlet.wsgi
差?
我真的很好奇,因为它们对我来说整体看起来很相似。
答案 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)
很抱歉迟到的回复。
基准中的性能差异主要有两个主要原因:
“在现实世界中”只发生在“slashdot”爆发的交通中。哪个是重要的,应该做好准备,但是当它发生时,您会通过添加更多服务器或禁用资源繁重的功能来做出反应。我没有看到在负载增加时实际添加更多服务器的基准测试。
另一方面,如果基准测试会模拟“正常日”负载(从一个网站到另一个网站会有所不同),但通常可以近似为请求,随机暂停,重复。暂停越少 - 我们模拟的流量就越多。基准的客户端也必须模拟延迟。在Linux上,这可以使用awesome netem [1]来完成,否则,通过在recv / send调用之前放置一些小延迟(这将非常困难,因为基准测试通常使用更高级别的库)。
现在,如果满足这些条件,我们实际上会对IO绑定问题进行基准测试。但结果不会太棒:所有候选人都成功地提供了10,50甚至200 qps的负载。无聊,对吧?因此,我们可以测量延迟分布,服务99%请求的时间等.Gevent仍然会显示更好的结果。但这种差异并不令人印象深刻。