Python 调整芹菜以获得高性能

Python 调整芹菜以获得高性能,python,django,performance,rabbitmq,celery,Python,Django,Performance,Rabbitmq,Celery,我正在尝试发送约400个HTTP GET请求并收集结果。 我在django跑。 我的解决办法是用芹菜和蔬菜 要开始芹菜任务,我调用获取报告: def get_reports(self, clients, *args, **kw): sub_tasks = [] for client in clients: s = self.get_report_task.s(self, client, *args, **kw).set(queue='io_bound'

我正在尝试发送约400个HTTP GET请求并收集结果。 我在django跑。 我的解决办法是用芹菜和蔬菜

要开始芹菜任务,我调用获取报告

def get_reports(self, clients, *args, **kw):
    sub_tasks = []
    for client in clients:  
            s = self.get_report_task.s(self, client, *args, **kw).set(queue='io_bound')
        sub_tasks.append(s)
    res = celery.group(*sub_tasks)()
    reports = res.get(timeout=30, interval=0.001)
    return reports

@celery.task
def get_report_task(self, client, *args, **kw):
    report = send_http_request(...)
    return report
我使用4个工人:

manage celery worker -P gevent --concurrency=100 -n a0 -Q io_bound
manage celery worker -P gevent --concurrency=100 -n a1 -Q io_bound
manage celery worker -P gevent --concurrency=100 -n a2 -Q io_bound
manage celery worker -P gevent --concurrency=100 -n a3 -Q io_bound
我使用RabbitMq作为代理

尽管它的运行速度比按顺序运行请求快得多(400个请求耗时约23秒),但我注意到大部分时间都是芹菜本身的开销,也就是说,如果我更改了get_report_task,如下所示:

@celery.task
def get_report_task(self, client, *args, **kw):
    return []
from feat.web import httpclient

pool = httpclient.ConnectionPool(host, port, maximum_connections=3)
整个操作耗时约19秒。 这意味着我只花了19秒时间将所有任务发送到芹菜,并将结果返回

rabbit mq的消息排队率似乎限制在每秒28条消息,我认为这是我的瓶颈

如果这很重要的话,我会在Win8机器上运行

我尝试过的一些事情:

  • 使用redis作为代理
  • 使用redis作为结果后端
  • 调整这些设置

    经纪人池限额=500

    CELERYD_预取_乘数=0

    CELERYD_每个孩子的最大任务数=100

    芹菜迟收=假

    芹菜禁用率限制=真


我正在寻找任何有助于加快速度的建议。

改用twisted怎么样?您可以获得更简单的应用程序结构。您可以一次从django进程发送所有400个请求,并等待它们全部完成。这可以同时工作,因为twisted将套接字设置为非阻塞模式,并且仅在数据可用时读取数据

不久前我也遇到了类似的问题,我在twisted和django之间建立了一个很好的桥梁。我在生产环境中运行它已经快一年了。你可以在这里找到它:。简单地说,它让主应用程序线程运行主twisted reactor循环,而django视图结果被委托给一个线程。它使用一个特殊的线程池,它公开了与reactor交互的方法,并使用了它的异步功能

如果您使用它,您的代码将如下所示:

from twisted.internet import defer
from twisted.web.client import getPage

import threading


def get_reports(self, urls, *args, **kw):
    ct = threading.current_thread()

    defers = list()
    for url in urls:
        # here the Deferred is created which will fire when
        # the call is complete
        d = ct.call_async(getPage, args=[url] + args, kwargs=kw)
        # here we keep it for reference
        defers.append(d)

    # here we create a Deferred which will fire when all the
    # consiting Deferreds are completed
    deferred_list = defer.DeferredList(defers, consumeErrors=True)
    # here we tell the current thread to wait until we are done
    results = ct.wait_for_defer(deferred_list)

    # the results is a list of the form (C{bool} success flag, result)
    # below unpack it
    reports = list()
    for success, result in results:
        if success:
            reports.append(result)
        else:
            # here handle the failure, or just ignore
            pass

    return reports
这仍然是一些你可以优化很多。在这里,对getPage()的每次调用都会创建一个单独的TCP连接,并在完成后关闭它。如果您的400个请求中的每一个都被发送到不同的主机,那么这将是最佳选择。如果不是这样,您可以使用http连接池,它使用持久连接和http管道。您可以这样实例化它:

@celery.task
def get_report_task(self, client, *args, **kw):
    return []
from feat.web import httpclient

pool = httpclient.ConnectionPool(host, port, maximum_connections=3)
而不是像这样执行单个请求(改为getPage()调用):


你真的在没有虚拟机的情况下运行Windows 8吗?我在运行OS X 10.7的2核Macbook 8GB RAM上进行了以下简单测试:

import celery
from time import time

@celery.task
def test_task(i):
    return i

grp = celery.group(test_task.s(i) for i in range(400))
tic1 = time(); res = grp(); tac1 = time()
print 'queued in', tac1 - tic1
tic2 = time(); vals = res.get(); tac2 = time()
print 'executed in', tac2 - tic2
我使用Redis作为代理,Postgres作为后端和默认工作程序,使用
--concurrency=4
。猜猜结果是什么?这是:

在3.5009469986中排队

于2.99818301201执行


事实证明我有两个不同的问题

首先,任务是一个成员方法。从课堂中提取出来后,时间下降到12秒左右。我只能假设这与自我的酸洗有关

第二件事是它在windows上运行。 在我的linux机器上运行之后,运行时间不到2秒。
我猜windows不是为了高性能而设计的。

这看起来很有趣,但芹菜已经在我的系统中使用了,所以我更喜欢使用它。如果我找不到解决办法,我会调查的。嘿!每秒28条消息的发布率非常低。我见过芹菜+librabbitmq在我的台式电脑上使用非持久性消息每秒执行100.000个任务。你真的只测量发送消息,还是还测量返回结果?Redis reusult后端未针对RPC进行优化。在开发版本(芹菜3.1版)中有一个新的RPC结果后端更适合于此。是否有更新?我注意到今天在一台Windows10机器上,芹菜需要3-4秒才能完成一个相对简单的任务。在Linux上这不是一个问题,但是对于Windows来说,延迟是很糟糕的,并且使产品基本上没有用处,因为在接收任务时线程会冻结。我想Linux是一个不错的产品,但这仍然让人恼火。