在进程上使用Celery并同时执行任务

时间:2012-11-02 11:10:52

标签: python multiprocessing celery gevent monkeypatching

我想使用Celery作为我的任务的队列,所以我的网络应用程序可以排队任务,返回响应,同时处理任务/某天/ ...我构建了一种API,所以我不知道提前会有什么类型的任务 - 将来,可能会有处理HTTP请求的任务,另一个IO,以及消耗CPU的任务。关于这一点,我想在流程上运行Celery的工作者,因为这些是Python中的通用类型的并行性。

但是,我也想在我的任务中使用gevent,所以我可以有一个任务产生许多HTTP请求,等等。问题是,当我这样做时:

from gevent import monkey
monkey.patch_all()

芹菜停止工作。它开始,但没有任何任务可以有效排队 - 他们似乎去经纪人,但芹菜工人不收集它们并处理它们。只有开始和等待。如果我删除这些行并执行任务而没有任何gevent和并行化,一切正常。

我认为这可能是因为gevent补丁也在线程化。所以我试过

from gevent import monkey
monkey.patch_all(thread=False)

...但是Celery甚至没有启动,它在没有给出理由的情况下崩溃(启用了日志记录的调试级别)。

是否可以使用Celery将任务排入队列并在单个任务中执行某些操作?怎么样?我做错了什么?

4 个答案:

答案 0 :(得分:19)

我认为启动任务的推荐方法如下。

python manage.py celery worker -P gevent --loglevel=INFO

Gevent需要尽早修补。

答案 1 :(得分:9)

您可以使用包含多个greenlet的多个线程运行芹菜,如下所示:

$ celery multi start 4 -P gevent -l info -c:1-4 1000

答案 2 :(得分:3)

根据我的奇怪经验,Celery Beat无法与具有gevent池的工作人员正常工作(计划任务被阻止并永远等待),除非您为Beat流程激活gevent monkey补丁。

但是,celery beat不支持--pool=gevent-P gevent选项。注入gevent monkey补丁的正确方法是使用curstomized celery二进制文件,例如:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from gevent import monkey
monkey.patch_all()

import re
import sys

from celery.__main__ import main

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

将其另存为celery-gevent,然后按如下方式运行Beat服务:

celery-gevent beat --app=proj.celery:app --loader=djcelery.loaders.DjangoLoader -f /var/log/celery/beat.log -l INFO --workdir=/my/proj --pidfile=/var/run/celery/beat.pid

proj.celery中,您还应该修补Django连接以避免DatabaseError

from __future__ import absolute_import

import os
# Set the Django settings module for the 'celery' program
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')

import django
# Load Django model definitions, etc
django.setup()

from django.db import connection
# Allow thread sharing to ensure that Django database connection
# works properly with gevent.
connection.allow_thread_sharing = True

from django.conf import settings
from celery import Celery

app = Celery('proj')

# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

(以上示例适用于Python 2.7.10,Celery 3.1.18,Django 1.8.2和gevent 1.0.2)

答案 3 :(得分:2)

据我所知,不可能。如果有人找到了更好的答案,我会接受它,而不是我的。

唯一的选择是将gevent也用作Celery工作者的后端。为了完成这样的事情,必须做的是在配置文件中添加以下内容:

CELERYD_POOL = 'gevent'

可以找到有关此选项的更多详细信息here。有关gevent池的更多信息是on this page。请注意,gevent池仍然标记为实验性的。我发现没有基准可用于比较不同任务的进程和异步gevent池(面向IO的任务,面向CPU的任务),但最后我意识到即使我的 CPU绑定任务实际上也会更多IO比CPU,因为我使用数据库来保存结果和数据库连接将是一个瓶颈,而不是计算部分。我将没有任何能够真正击中CPU的科学任务。