threads - programa de hilos en python
Uso de Celery en procesos y gevent en tareas al mismo tiempo. (4)
Me gustaría usar Celery como una cola para mis tareas para que mi aplicación web pueda poner en cola una tarea, devolver una respuesta y la tarea se procesará mientras tanto / algún día / ... Construyo una especie de API, por lo que no Sepa qué tipo de tareas habrá de antemano. En el futuro, puede haber tareas relacionadas con solicitudes HTTP, otra IO, pero también tareas que consumen CPU. Con respecto a eso, me gustaría dirigir a los trabajadores de Celery en los procesos, ya que estos son un paralelismo de tipo universal en Python.
Sin embargo, también me gustaría usar gevent en mis tareas, por lo que podría hacer que una sola tarea genere muchas solicitudes HTTP, etc. El problema es que cuando hago esto:
from gevent import monkey
monkey.patch_all()
El apio se detiene para trabajar. Comienza, pero no se pueden poner en cola tareas en forma efectiva; parece que van al intermediario, pero el trabajador de Celery no las recoge y las procesa. Solo comienza y espera. Si borro esas líneas y realizo la tarea sin ningún gevent ni paralelización, todo funciona.
Creo que podría ser porque los parches gevent también se enhebran. Así que lo intenté
from gevent import monkey
monkey.patch_all(thread=False)
... pero luego Celery ni siquiera se inicia, se bloquea sin dar una razón (el nivel de depuración del registro está activado).
¿Es posible usar Celery para poner en cola tareas y gevent para hacer algunas cosas dentro de una sola tarea? ¿Cómo? ¿Qué hago mal?
Creo que la forma recomendada para comenzar la tarea es la siguiente.
python manage.py celery worker -P gevent --loglevel=INFO
Gevent necesita ser reparado lo antes posible.
Desde mi extraña experiencia, Celery Beat no puede funcionar correctamente con trabajadores con gevent pool (las tareas programadas están bloqueadas y esperan para siempre), a menos que active el parche de gevent monkey para el proceso de Beat.
Sin embargo, celery beat
no admite la --pool=gevent
o -P gevent
. La forma correcta de inyectar parches de gevent monkey es usar un binario curstomized de celery
, como:
#!/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
como celery-gevent
y ejecute el servicio Beat de la siguiente manera:
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
En proj.celery
también deberías parchear la conexión Django para evitar 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)
(El ejemplo anterior funciona para Python 2.7.10, Celery 3.1.18, Django 1.8.2 y gevent 1.0.2)
Por lo que pude aprender, esto no es posible . Si alguien encuentra una mejor respuesta, la aceptaré en lugar de esta mía.
La única opción es usar gevent también como backend para los trabajadores de Celery. Lo que uno tiene que hacer para lograr tal cosa es agregar lo siguiente en el archivo de configuración:
CELERYD_POOL = ''gevent''
Más detalles sobre estas opciones se pueden encontrar here . Más información sobre la piscina de gevent está en esta página . Tenga en cuenta el hecho de que el grupo de gevent todavía está marcado como experimental. No encontré puntos de referencia disponibles para comparar procesos y async gevent pool en diferentes tareas (tareas orientadas a IO, tareas orientadas a la CPU), pero finalmente me di cuenta de que incluso mis tareas relacionadas con la CPU serán de hecho más IO que CPU, porque uso la base de datos para guardar resultados y la conexión de la base de datos será un cuello de botella, no la parte informática. No tendré ninguna tarea científica que realmente afecte a la CPU.
Puede ejecutar el apio con varios hilos que contienen varios greenlets como este:
$ celery multi start 4 -P gevent -l info -c:1-4 1000