4

正如celery 文档中所提到的,对于诸如异步 HTTP 请求之类的事件 I/O,eventlet 池应该比 prefork 池更快。

他们甚至提到

“在使用 feed hub 系统的非正式测试中,Eventlet 池每秒可以获取和处理数百个 feed,而 prefork 池花费 14 秒处理 100 个 feed。”

但是,我们无法产生任何与此类似的结果。完全按照描述运行示例任务urlopencrawl并打开数千个 url,似乎 prefork 池几乎总是表现得更好。

我们测试了各种并发(并发 200 的 prefork,并发 200、2000、5000 的 eventlet)。在所有这些情况下,使用 prefork 池在更短的时间内完成任务。正在运行的机器是运行 RabbitMQ 服务器的 2014 Macbook Pro。

我们希望一次发出数千个异步 HTTP 请求,并且想知道 eventlet 池是否值得实现?如果是,我们缺少什么?

python -V && pip freeze 的结果是:

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()
4

1 回答 1

4

Eventlet 允许您拥有比 prefork 更高的并发性,甚至无需编写非阻塞式代码。Eventlet 优于 prefork 的典型情况是当您有许多阻塞 I/O 绑定操作时(例如time.sleeprequests.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)

以同样的方式运行worker,最终产生任务

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 个子进程的 prefork worker 和另一个具有 1000 个绿色线程的 worker,您将能够看到巨大的差异。

于 2018-05-10T03:59:42.097 回答