web-dev-qa-db-ja.com

プロセスでのCeleryとタスクでのgeventを同時に使用する

Celeryをタスクのキューとして使用したいので、私のWebアプリがタスクをエンキューし、応答を返し、その間にタスクが処理されます/いつか/ ...一種のAPIを構築するので、私はしませんどのような種類のタスクが事前に存在するかを把握します。将来的には、HTTP要求を処理するタスク、別のIOだけでなく、CPUを消費するタスクも存在する可能性があります。これに関しては、Celeryのワーカーをプロセスで実行したいと思います。これらはPythonの普遍的な種類の並列処理であるためです。

ただし、自分のタスクでもgeventを使用したいので、単一のタスクで多数のHTTPリクエストなどを生成することができます。問題は、これを実行するときです。

from gevent import monkey
monkey.patch_all()

セロリは動作を停止します。それは開始しますが、効果的にキューに入れることができるタスクはありません-それらはブローカーに行くようですが、Celeryワーカーはそれらを収集して処理しません。開始して待機するだけです。これらの行を削除して、geventと並列化なしでタスクを実行すると、すべてが機能します。

Geventパッチもスレッド化していることが原因かもしれません。だから私は試した

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

...しかし、Celeryは起動さえせず、理由を示さずにクラッシュします(デバッグレベルのロギングがオンになっています)。

タスクをエンキューするためにCeleryを使用し、単一のタスク内で何かを行うためにgeventを使用することは可能ですか?方法?何が悪いのですか?

26
Honza Javorek

タスクを開始するための推奨される方法は次のとおりだと思います。

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

Geventはできるだけ早くパッチを適用する必要があります。

19
myusuf3

次のように、複数のグリーンレットを含む複数のスレッドでセロリを実行できます。

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

私の奇妙な経験から、Celery Beatは、geventモンキーパッチを有効にしない限り、geventプール(スケジュールされたタスクがブロックされ、永久に待機する)を持つワーカーと適切に連携できません。

ただし、celery beat--pool=geventまたは-P geventオプションをサポートしていません。 gevent monkeyパッチを注入する適切な方法は、次のように、カスタマイズされた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
Rockallite

私が学んだ限り、これは不可能です。誰かがより良い答えを見つけた場合、私はこの鉱山の代わりにそれを受け入れます。

唯一のオプションは、geventをCeleryワーカーのバックエンドとしても使用することです。そのようなことを達成するために必要なことは、設定ファイルに以下を追加することです:

CELERYD_POOL = 'gevent'

このオプションの詳細については、 ここ を参照してください。 geventプールの詳細は このページ です。 geventプールがまだ実験的としてマークされているという事実に注意してください。異なるタスク(IO指向のタスク、CPU指向のタスク)でプロセスと非同期geventプールを比較するために利用できるベンチマークは見つかりませんでしたが、最終的にCPU-boundタスクでも実際には、より多くのIO CPUよりも多く、データベースを使用して結果を保存しているため、データベース接続がボトルネックになり、計算部分ではありません。CPUに実際に影響する科学的なタスクはありません。 。

2
Honza Javorek