正如在芹菜文档中提到的,对于异步HTTP请求等事件I/O,eventlet池应该比prefork池更快。
他们甚至提到
"在使用提要集线器系统的非正式测试中,Eventlet池可以每秒获取和处理数百个提要,而预处理池花了14秒处理100个提要。">
然而,我们无法产生任何类似的结果。运行示例任务,urlopen和crawl完全按照描述,并打开数千个url,似乎预工作池总是表现得更好。
我们测试了各种并发性(prefork with concurrencies 200,eventlet with concurrancies 200、2000、5000)。在所有这些情况下,使用预工作池可以在更短的秒内完成任务。正在运行的机器是一台运行RabbitMQ服务器的2014 Macbook Pro。
我们希望一次发出数千个异步HTTP请求,并想知道eventlet池是否值得实现?如果是,我们缺少什么?
的结果python-V&;pip冻结是:
Python 2.7.6
amqp==1.4.6
anyjson==0.3.3
billiard==3.3.0.20
bitarray==0.8.1
celery==3.1.18
dnspython==1.12.0
eventlet==0.17.3
greenlet==0.4.5
kombu==3.0.26
pybloom==1.1
pytz==2015.2
requests==2.6.2
wsgiref==0.1.2
使用的测试代码(几乎完全来自文档):
>>> from tasks import urlopen
>>> from celery import group
>>> LIST_OF_URLS = ['http://127.0.0.1'] * 10000 # 127.0.0.1 was just a local web server, also used 'http://google.com' and others
>>> result = group(urlopen.s(url)
... for url in LIST_OF_URLS).apply_async()
Eventlet允许您拥有比prefork更大的并发性,即使不必编写非阻塞风格的代码。Eventlet优于prefork的典型情况是,您有许多阻塞I/O绑定操作(例如,对高延迟网站的time.sleep
或requests.get
)。似乎您对本地主机或http://google.com"得到的响应太快,无法被视为有I/O限制。
您可以尝试这个玩具示例,看看基于Eventlet的池如何在I/O绑定操作中表现得更好。
# in tasks.py add this function
import time
# ...
@task()
def simulate_IO_bound():
print("Do some IO-bound stuff..")
time.sleep(5)
以相同的方式运行工作人员,并最终生成任务
from tasks import simulate_IO_bound
NUM_REPEAT = 1000
results = [simulate_IO_bound.apply_async(queue='my') for i in range(NUM_REPEAT)]
for result in results:
result.get()
假设您有一个具有100个子流程的预处理工作者和另一个具有1000个绿色线程的工作者,您将能够看到显著的差异。