Celery: Les tùches ne sont pas autorisées à démarrer des sous-processus

CrĂ©Ă© le 29 nov. 2013  Â·  68Commentaires  Â·  Source: celery/celery

À partir de Celery 3.1.0, le pool de processus ( celery.concurrency.prefork , anciennement celery.concurrency.processes ) utilise des processus dĂ©mons pour effectuer des tĂąches.

Les processus démons ne sont pas autorisés à créer des processus enfants et, par conséquent, les tùches qui utilisent le package multiprocessing ne fonctionnent pas:

[2013-11-29 14:27:48,297: ERROR/MainProcess] Task app.add[e5d184c0-471f-4fc4-804c-f760178d4847] raised exception: AssertionError('daemonic processes are not allowed to have children',)
Traceback (most recent call last):
  File "/Users/aromanovich/Envs/celery3.1/lib/python2.7/site-packages/celery/app/trace.py", line 218, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/Users/aromanovich/Envs/celery3.1/lib/python2.7/site-packages/celery/app/trace.py", line 398, in __protected_call__
    return self.run(*args, **kwargs)
  File "/Users/aromanovich/Projects/celery/app.py", line 10, in add
    manager = multiprocessing.Manager()
  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/__init__.py", line 99, in Manager
    m.start()
  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/managers.py", line 524, in start
    self._process.start()
  File "/usr/local/Cellar/python/2.7.6/Frameworks/Python.framework/Versions/2.7/lib/python2.7/multiprocessing/process.py", line 124, in start
    'daemonic processes are not allowed to have children'
Not a Bug

Commentaire le plus utile

@thedrow
Tu as mal compris. À deux reprises.
Notre souci n'est pas que vous n'ayez pas la ressource (c'est parfaitement compréhensible, et, malheureusement, un cas trÚs courant dans le logiciel libre). Notre préoccupation est que le ticket est fermé à cause de cela, ce n'est pas ainsi que les tickets fonctionnent.
Nous ne sommes pas «malheureux», nous sommes choqués.

Tous les 68 commentaires

Cela n'a pas changé entre 3.0 et 3.1, donc je ne sais pas pourquoi vous obtiendriez cette erreur maintenant et pas avant.

C'est ainsi que cette erreur peut ĂȘtre reproduite.

app.py:

import multiprocessing
from celery import Celery

app = Celery(__name__, broker='amqp://192.168.33.40')
@app.task
def f():
    manager = multiprocessing.Manager()

sendtask.py:

import app

app.f.delay()

Je lance worker en utilisant la commande suivante: celery worker -A app.app -l debug .

Avec Celery 3.0.24, la tùche réussit:

[2013-12-02 20:43:56,454: INFO/MainProcess] Task app.f[bcaab028-dbec-43a8-9259-ff7c35ff13d0] 
succeeded in 0.0169339179993s: None

Avec Celery 3.1.5, il ne:

[2013-12-02 20:48:38,946: ERROR/MainProcess] Task app.f[c9f1cdd3-ae38-493e-b7c7-b9636ed473d0] 
raised exception: AssertionError('daemonic processes are not allowed to have children',)

Ma comprĂ©hension du problĂšme est la suivante: celery.concurrency.prefork.TaskPool utilise celery.concurrency.asynpool.AsynPool ; AsynPool hĂ©rite de billiard.pool.Pool qui gĂ©nĂšre des processus de travail dĂ©mon et AsynPool ne remplace pas ce comportement. Mais vous avez raison, ce schĂ©ma ne semble pas ĂȘtre changĂ© entre 3.0 et 3.1, donc je suis aussi confus :)

Et il semble que je ne sois pas seul avec ce problĂšme: http://stackoverflow.com/questions/20149421/threads-in-celery-3-1-5

Une diffĂ©rence est que le processus de travail est maintenant une sous-classe de 'Process', oĂč avant d'utiliser l'argument de fonction: Process(target=) , il y a peut-ĂȘtre une diffĂ©rence dans les valeurs par dĂ©faut pour ces approches.

multitraitement et anciennes versions des ensembles de billard daemon=True :
https://github.com/celery/billiard/blob/2.7/billiard/pool.py#L904

Et c'est pareil dans la derniĂšre version:
https://github.com/celery/billiard/blob/3.3/billiard/pool.py#L1039

Je pense que le processus de tĂąche Ă©tant un dĂ©mon prĂ©sente une limitation sĂ©rieuse pour la mise en Ɠuvre des tĂąches.
J'ai écrit une tùche qui utilise le multitraitement pour accélérer les opérations liées au processeur. Tout fonctionne bien lorsque je démarre un ouvrier dans un terminal comme suit:

céleri ouvrier --app = tùches -Q wb -l info --concurrency = 1

Mais lorsque j'utilise le script celeryd pour démarrer un worker, j'obtiens cette exception:
AssertionError: les processus démoniaques ne sont pas autorisés à avoir des enfants

J'ai compris ce qui avait provoqué le changement de comportement.
Les tùches sont exécutées à l'aide de processus démon à la fois dans 3.0 et 3.1, mais jusqu'à ce que celery / billiard @ 4c32d2e et https://github.com/celery/billiard/commit/c676b94aa4144349b11ab31c82296a5d804909c9 multiprocessing module n'en était pas conscient et par conséquent permettait de créer des sous-processus.

À ma connaissance, il y avait un bogue avant la version 3.1 (les tĂąches Ă©taient autorisĂ©es Ă  crĂ©er des sous-processus, ce qui pouvait entraĂźner un Ă©tat orphelin) et maintenant ce bogue a Ă©tĂ© corrigĂ©.

La dĂ©cision de ne pas autoriser les processus de dĂ©mon python Ă  bifurquer me semble plutĂŽt arbitraire. Bien que j'en reconnaisse la bonne foi, je pense que je devrais ĂȘtre en mesure d'avoir un contrĂŽle total sur ce comportement si je le souhaite.

Être liĂ© Ă  un processus par tĂąche me semble ĂȘtre une sĂ©rieuse limitation. PensĂ©es?

Je me demande pourquoi cette limitation est lĂ  en premier lieu, un avertissement que je peux comprendre, mais le rejeter purement et simplement semble ridicule lorsque vous ĂȘtes parfaitement capable de bifurquer des processus en utilisant d'autres moyens.

@ask , serait-il possible d'initialiser le processus de travail du céleri avec l'indicateur de démon False? Ou rendre cela configurable?

@ilyastam semble que nous commentions en mĂȘme temps

Je conviens que cela semble ĂȘtre une limitation arbitraire, mais j'aurais aimĂ© connaĂźtre la raison d'ĂȘtre de son ajout en premier lieu.

C'est un piÚge bien connu dans les systÚmes posix, mais il est toujours autorisé. Vous pouvez nettoyer les processus enfants dans un gestionnaire de signaux, bien que cela ne vous protÚge pas contre SIGKILL.

Je pense que nous devrions supprimer la limitation du billard, mĂȘme si cela divergerait du comportement multitraitement. Vous pouvez toujours crĂ©er des processus enfants en utilisant le module subpocess ou en utilisant l'appel de bas niveau fork , donc les utilisateurs expĂ©rimentĂ©s devraient pouvoir crĂ©er des instances enfants billiard.Process .

@ilyastam Devrait ĂȘtre capable de supprimer l'instruction rise, pas besoin de rendre les processus "non-dĂ©mon"

Autrement dit, les processus dĂ©mons seront autorisĂ©s Ă  crĂ©er des processus enfants mĂȘme s’ils ne pourront pas les rĂ©colter,
c'est comme ça que posix fonctionne de toute façon.

Btw, notez que ce n'est pas une raise , c'est une instruction assert, qui sera supprimée si python est démarré avec l'argument PYTHONOPTIMIZE envvar ou -O .

billiard 3.3.0.11 est sur PyPI, y compris ce changement

@ask merci. Une idée de la version du céleri qui verra cette amélioration?

multiprocessing indique explicitement que les processus démons ne sont pas autorisés à créer des sous - cette déclaration assert ressemble plus à ce qu'elle a été placée ici comme un raccourci pour raise (les gens le font souvent).

Cette limitation est documentée et je ne pense pas que ce soit une bonne idée pour Celery de patcher silencieusement un singe multiprocessing et de l'enlever. Cela pourrait avoir des conséquences vraiment inattendues et néfastes.

Je peux penser Ă  l'exemple suivant (cela peut sembler un peu artificiel, cependant):

@app.task
def f():
    p = multiprocessing.Pool(3)
    p.map_async(time.sleep, [1000, 1000, 1000])

Étant exĂ©cutĂ© comme une simple fonction Python, ce code fonctionne correctement. Mais Ă©tant exĂ©cutĂ© en tant que tĂąche Celery (en utilisant Celery version 3.0. *), Il laisse trois sous-processus qui seront suspendus pour toujours; lorsque l'ouvrier Celery quitte, ces sous-processus deviennent orphelins.

Cela n'explique pas pourquoi, il indique simplement le comportement Unix auquel vous vous attendez lors du dĂ©marrage d'un processus enfant-enfant. MĂȘme si c'est une limitation infĂąme dans unix, cela n'empĂȘche pas les gens de le faire. Ce n'est pas diffĂ©rent de
dĂ©marrer un processus subprocess.Popen , ou mĂȘme appeler fork() pour dĂ©marrer un nouveau processus. Alors pourquoi devrait-il ĂȘtre illĂ©gal?

La façon de faire votre exemple:

from billiard import Pool
from multiprocessing.util import Finalize

_finalizers = []

@app.task
def f():
    p = billiard.Pool(3)
    _finalizers.append(Finalize(p, p.terminate))
   try:
       p.map_async(time.sleep, [1000, 1000, 1000])
       p.close()
       p.join()
   finally:
       p.terminate()

Pour tuer (-9) cela, vous devrez Ă©galement tuer -9 les processus enfants, mais c'est quelque chose que vous aurez
Ă  prendre en compte pour tous les processus Unix.

Non pas que je préconise de créer un pool pour chaque tùche, mais je ne vois pas pourquoi les utilisateurs, qui savent ce qu'ils
faire, ne devrait pas ĂȘtre autorisĂ© Ă  dĂ©marrer des processus Ă  partir d'une tĂąche.

De plus, nous ne corrigeons rien de singe, il s'agit uniquement d'un changement de billard.

De plus, nous ne corrigeons rien de singe, il s'agit uniquement d'un changement de billard.

Par "monkey patching", j'entends cette affectation, qui remplace multiprocessing._current_process par une instance de billiard.process.Process : https://github.com/celery/billiard/blob/master/billiard/process.py # L53.

Je conviens qu'il n'y a rien de mal à démarrer des processus enfant-enfant s'ils sont bien gérés (comme dans votre exemple). Mon point est que multiprocessing n'est pas écrit de cette façon et nous ne devons pas ignorer ses limitations de _implémentation_.

@aromanovich Cela ne peut pas ĂȘtre Ă©crit autrement, ce n'est pas une limitation du multitraitement, c'est une limitation d'unix.

Il dĂ©finit _current_process afin que la variable de format des modules de journalisation processName fonctionne, et que l'objet de processus de billard ait la mĂȘme API que l'objet de processus multitraitement afin qu'il soit sĂ»r de dĂ©finir le processus actuel.

Et d'ailleurs, vous devrez utiliser le billard pour que la limitation soit levée, l'utilisation du multitraitement lÚvera toujours l'exception.

Pourrait également résoudre ce problÚme en utilisant cette approche:
http://stackoverflow.com/questions/6974695/python-process-pool-non-daemonic
Ce qui permettrait aux utilisateurs de continuer Ă  utiliser le module multitraitement, Ă©vitant ce problĂšme:
https://github.com/celery/billiard/issues/99

J'obtiens cette erreur lors de l'appel d'une tĂąche de tissu

@celery.task
def dostuff():
   execute(fabfile.push_settings, sid=site['sid'])

<strong i="7">@parallel</strong>
@roles(environment)
def push_settings(sid):
  #do stuff

@frodopwns utilise ENV
export PYTHONOPTIMIZE = 1
pour supprimer cette affirmation. vous devez gérer toutes choses.

@xiaods Je pense avoir résolu ce problÚme avec quelque chose comme ceci:

@worker_process_init.connect
def configure_workers(sender=None, conf=None, **kwargs):
    Crypto.Random.atfork()

ProblĂšme

J'ai une tĂąche qui calcule certaines donnĂ©es et charge un classificateur scikit-learn pour faire des prĂ©dictions basĂ©es sur ces donnĂ©es. Lorsque j'exĂ©cute la tĂąche par elle-mĂȘme, tout va bien, mais lorsque je l'exĂ©cute Ă  l'aide de cĂ©leri, j'obtiens une erreur lorsque la tĂąche tente de charger le classificateur marinĂ©:

[2015-07-17 21:23:51,299: ERROR/MainProcess] Task app.f[329d0da4-2e0e-4e1f-8148-d64f47750b1f] raised unexpected: AttributeError("'Worker' object has no attribute '_config'",)
Traceback (most recent call last):
  File "/home/username/anaconda3/lib/python3.4/site-packages/celery/app/trace.py", line 240, in trace_task
    R = retval = fun(*args, **kwargs)
  File "/home/username/anaconda3/lib/python3.4/site-packages/celery/app/trace.py", line 438, in __protected_call__
    return self.run(*args, **kwargs)
  File "/home/username/working/playground/celery/app.py", line 11, in f
    clf = pickle.load(open('clf.pickle', 'rb'))
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/ensemble/__init__.py", line 6, in <module>
    from .base import BaseEnsemble
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/ensemble/base.py", line 13, in <module>
    from ..externals.joblib import cpu_count
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/externals/joblib/__init__.py", line 112, in <module>
    from .parallel import Parallel
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/externals/joblib/parallel.py", line 23, in <module>
    from ._multiprocessing_helpers import mp
  File "/home/username/anaconda3/lib/python3.4/site-packages/sklearn/externals/joblib/_multiprocessing_helpers.py", line 25, in <module>
    _sem = mp.Semaphore()
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/context.py", line 81, in Semaphore
    return Semaphore(value, ctx=self.get_context())
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/synchronize.py", line 127, in __init__
    SemLock.__init__(self, SEMAPHORE, value, SEM_VALUE_MAX, ctx=ctx)
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/synchronize.py", line 59, in __init__
    kind, value, maxvalue, self._make_name(),
  File "/home/username/anaconda3/lib/python3.4/multiprocessing/synchronize.py", line 117, in _make_name
    return '%s-%s' % (process.current_process()._config['semprefix'],
AttributeError: 'Worker' object has no attribute '_config'

Reproduire

Créez un classificateur vide et enregistrez-le sous forme de cornichon:

import pickle
from sklearn.ensemble import GradientBoostingClassifier
clf = GradientBoostingClassifier()
pickle.dump(clf, open('clf.pickle', 'wb'))

Créez une application simple ( app.py ):

import pickle
import sklearn
from celery import Celery

app = Celery(__name__, broker='amqp://localhost//')

@app.task
def f():
    print('hello')
    clf = pickle.load(open('clf.pickle', 'rb'))
    print(clf)

Démarrez le céleri-ouvrier:

celery -A app worker --loglevel=debug

Exécutez l'application:

python -c "from app import f; f.delay()"

Message d'erreur:

...
AttributeError: 'Worker' object has no attribute '_config'

Solution

Je pense qu'il devrait y avoir une option pour "monkeypatch" Celery pour permettre aux tĂąches de dĂ©marrer des sous-processus, surtout si une telle "fonctionnalitĂ©" existait dans le passĂ©. À l'heure actuelle, les gens s'Ă©loignent simplement vers d'autres frameworks lorsqu'ils rencontrent ce problĂšme: http://stackoverflow.com/questions/27904162/using-multiprocessing-pool-from-celery-task-raises-exception. Voici un autre exemple de cette erreur: http://stackoverflow.com/questions/22674950/python-multiprocessing-job-to-celery-task-but-attributeerror.

Ce numĂ©ro devrait ĂȘtre rouvert ...

Je viens de rencontrer le mĂȘme problĂšme. J'utilise nltk dans l'un de mes workers qui Ă  son tour importe scikit-learn ce qui conduit Ă  la mĂȘme erreur que @ostrokach a montrĂ©e.

Il semble que je puisse contourner ce problĂšme avec le code suivant:

from celery.signals import worker_process_init

@worker_process_init.connect
def fix_multiprocessing(**kwargs):
    from multiprocessing import current_process
    try:
        current_process()._config
    except AttributeError:
        current_process()._config = {'semprefix': '/mp'}

C'est Ă©videmment un hack trĂšs grossier et je ne sais pas ce qui se passerait si j'utilisais vraiment le multitraitement (diable je ne sais mĂȘme pas ce qu'est semprefix ) mais c'est suffisant pour faire scikit-learn travailler Ă  nouveau.

Je laisse cela ici pour d'autres personnes qui trĂ©buchent sur le mĂȘme problĂšme jusqu'Ă  ce que ce problĂšme soit rĂ©solu.

Serait-ce une sorte d'incompatibilité avec le billard sur Python 3? Ou est-il également reproductible sur Python 2?

Le problÚme initial des processus de céleri ne pouvant pas créer de sous-processus est-il toujours un problÚme? En regardant en arriÚre dans les commentaires, cela a été corrigé avec celery / billiard @ e6bb0f7 pour la version 3.3. Cependant, un commit ultérieur (celery / billiard @ c7eedbd0ee1498e76d4fa1affac5b1a275660ee7) a réintroduit une instruction assert trÚs similaire dans la méthode de démarrage pour 3.4. Aucun problÚme pour moi puisque je suis sur 3.3, mais je voulais juste le signaler si cela pouvait créer des problÚmes dans le futur.

@martinth Merci, ce hack fonctionne pour moi aussi!

@xiaods Merci! Votre solution fonctionne pour moi! Merci!

@gilinson c'est toujours un problĂšme et exporter PYTHONOPTIMIZE = 1 le "corrige en quelque sorte".
Je viens de rencontrer le mĂȘme problĂšme, en essayant d'exĂ©cuter un playbook ansible dans la tĂąche Celery

@martinth Merci pour le hack! Je rencontre le mĂȘme problĂšme avec:

  • Python 3.4.3
  • cĂ©leri == 3.1.18
  • scikit-learn == 0,17

Le hack de @martinth ne fonctionne pas pour moi, j'ai rencontré ce

L'utilisation du multiprocessing.dummy basé sur les threads a fonctionné dans le céleri pour moi:

from multiprocessing.dummy import Pool

Cette erreur se produit également dans python 2.7.5. Je ne sais pas s'il est destiné à y remédier, mais cela rend l'utilisation de salt-ssh de saltstack inutilisable avec du céleri.

ClĂŽture, car nous n'avons pas les ressources pour mener Ă  bien cette tĂąche.

Solution possible"

J'avais une telle tĂąche qui essayait de crĂ©er des threads et cela Ă©chouerait. J'ai rĂ©ussi Ă  le faire fonctionner en: forçant Ă  un script bash qui lui-mĂȘme renvoie Ă  un interprĂ©teur python qui fait exactement le mĂȘme code (et pourrait donc crĂ©er des threads, ce qui Ă©tait essentiel pour mon cas d'utilisation).

Je ne comprends pas pourquoi le ticket est fermé. Si vous ne disposez pas de ressources pour cela, vous pouvez faire un commentaire à ce sujet, mais cela ne ferme pas le ticket. Vous cachez simplement le bogue en le faisant.

Ce qui est particuliÚrement mauvais pour un ticket étiqueté «critique» à la fois pour la priorité et la gravité.

@orzel +1.
Priorité: critique
Gravité: critique
ClĂŽture, car nous n'avons pas les ressources pour mener Ă  bien cette tĂąche.

C'est une blague. Si vous n'avez pas de ressources maintenant, ne le réparez pas maintenant. Corrigez-le lorsque vous aurez des ressources. La fermeture du ticket ne résoudra pas le problÚme

@orzel @Templarrr J'ai étiqueté ce ticket comme critique, donc @ask n'est pas à blùmer ici.
Vous pourriez ĂȘtre mĂ©content de cela, mais protester n'aidera pas.
Nous devons préparer notre arriéré en fonction de ce qui est exploitable et de ce qui ne l'est pas et actuellement ce n'est pas le cas.
C'est un appel difficile Ă  faire, mais quelqu'un doit le faire.
Si ce problĂšme vous gĂȘne, essayez de le rĂ©soudre. Je promets que si le correctif est correct et a les tests appropriĂ©s, je le fusionnerai.

@thedrow
Tu as mal compris. À deux reprises.
Notre souci n'est pas que vous n'ayez pas la ressource (c'est parfaitement compréhensible, et, malheureusement, un cas trÚs courant dans le logiciel libre). Notre préoccupation est que le ticket est fermé à cause de cela, ce n'est pas ainsi que les tickets fonctionnent.
Nous ne sommes pas «malheureux», nous sommes choqués.

Je suis également complÚtement en désaccord avec la fermeture de ceci.

Je pense que nous pouvons tous convenir que ce _is_ en effet un bogue. Et bien qu'il soit en effet triste qu'il n'y ait pas assez de ressources, la fermeture d'un bogue _definite_ n'aidera pas cela. Vous ne pouvez pas savoir si peut-ĂȘtre que demain quelqu'un arrive longtemps et pense "corrigeons quelques bugs dans Celery" juste pour examiner les problĂšmes en suspens et pense "Eh bien, il n'y a pas de travail intĂ©ressant Ă  faire ici ... travaillons sur _OtherProject_ Ă  la place ".
De plus, la fermeture de ce problÚme rendra sa recherche plus difficile. Je ne sais pas comment vous utilisez Github, mais lorsque je découvre un problÚme potentiel, je recherche d'abord dans le suivi des problÚmes un problÚme ouvert. Généralement, il y a beaucoup de discussions et plus jamais il n'y a aussi une solution de contournement (comme dans ce cas) que je peux utiliser pour le moment. Ce n'est que si je suis vraiment désespéré que je commence à examiner les problÚmes fermés.

Ce n'est pas du «toilettage de l'arriĂ©ré», c'est un ajustement des nombres. Si je regarde les choses Ă  utiliser, je regarde le nombre de problĂšmes ouverts, mais je regarde aussi toujours le nombre d'Ă©toiles (qui est assez Ă©levĂ© pour le cĂ©leri). Je comprends qu'il est souhaitable d'avoir un faible nombre de bogues pour l'attrait du public, mais aussi pour votre propre bien. HonnĂȘtement, je comprends que voir "250 problĂšmes en suspens" n'est pas un bon nombre et semble accablant.

Si vous n'avez pas la main-d'oeuvre pour travailler lĂ -dessus dans le prochain mois (ou mĂȘme l'annĂ©e) _c'est bien_. Ne fermez pas. Une clĂŽture ne devrait se produire que si le problĂšme est rĂ©solu ou si il est "absolument clair" qu'il ne sera "jamais_ fait". Les deux ne sont pas le cas ici.

Supprimez simplement les indicateurs «Critique» et ajoutez un indicateur «Reporté» pour tout ce qui ne peut pas ĂȘtre gĂ©rĂ© maintenant mais qui devrait ĂȘtre gĂ©rĂ© si la ressource _est_ disponible.

Je ne suis pas sûr que nous puissions résoudre le problÚme. Nous ne pouvons pas changer le fonctionnement d'Unix mais nous pourrions soumettre un correctif en amont pour lever la restriction?

Il existe peut-ĂȘtre des solutions spĂ©cifiques Ă  la plate-forme sous Linux, mais cela devrait ĂȘtre recherchĂ©. Il est ouvert depuis 2 ans sans que personne ne soit incitĂ© Ă  le rĂ©parer, il est donc peu probable qu'il soit corrigĂ© dans la fonction proche.

J'ai fermĂ© plus de 200 problĂšmes et marquĂ© plus de 30 000 e-mails comme lus, donc certains d'entre eux sont forcĂ©ment litigieux et nous devrons peut-ĂȘtre les rouvrir. Je m'attends complĂštement Ă  cela, mais ce serait bien si nous pouvions Ă©galement contribuer Ă  une solution, par exemple en aidant Ă  documenter le dĂ©faut si c'est la seule option connue.

Nous sommes débordés de travail, essayant de gérer un énorme projet sans ressources. Nous ne sommes pas en mesure de trier les problÚmes ou de savoir quels problÚmes ont déjà été résolus.

Bien, OK. Mais est-ce que le fait que «vous ne pouvez pas utiliser le multitraitement si vous Ă©crivez du code pour un cĂ©leri ouvrier» pourrait au moins ĂȘtre documentĂ©? Je veux dire ... il y aura toujours des gens qui ne le liront pas, mais au moins vous pouvez le pointer vers lui et dire "Voyez, c'est documentĂ©. Nous ne pouvons pas le changer.

Ma liste de tĂąches est gigantesque, vous pouvez maintenant Ă©diter la documentation directement sur github, donc c'est vraiment facile d'apporter des modifications comme celles-ci :(

Je ne fais pas cela pour cacher des problÚmes, je le fais pour inciter les gens à agir précisément parce que je veux que cela s'améliore.

@ask Pouvons-nous appliquer le multitraitement à l'intérieur de la tùche en utilisant le céleri dans Django?
Y a-t-il une alternative pour le faire?

@abhisheksachan, vous devriez lire tout ce problĂšme avant de publier une telle question

@abhisheksachan Je n'ai pas essayé cela depuis quelques années, mais je l'avais fait fonctionner en utilisant https://pypi.python.org/pypi/billiard car il permet la démonisation des sous-processus.

Ouais, vous devez remplacer les importations de 'multiprocessing' par 'billiard', par exemple:

from multiprocessing import Process

->

from billiard import Process

Il n'y a aucun moyen pour nous de désactiver la limitation du multitraitement, mais nous soutenons qu'il ne devrait pas y avoir de limitation de toute façon, donc notre fourchette de multitraitement le permet.

Pour tous ceux qui, comme moi, ont investi dans le développement d'un systÚme de mise en file d'attente _ AVANT_ découvrir cette limitation et ont besoin d'une solution de contournement différente jusqu'à ce qu'ils puissent migrer vers un wrapper python rabbitMQ plus utilisable, j'ai réussi à contourner le problÚme en appelant un sous-processus externe qui peut fourchez-vous proprement. Ce processus fourchu est maintenant en dehors du bac à sable de céleri et les choses fonctionnent comme il se doit.

Dans l'exemple OP, remplacez:

app = Celery(__name__, broker='amqp://192.168.33.40') 
@app.task
def f():
    manager = multiprocessing.Manager()

avec:

app = Celery(__name__, broker='amqp://192.168.33.40')
@app.task
def f():
    process = subprocess.Popen(["program"]) # or the newer post 3.5 run version
    process.wait()
    # analyze exit code

et le "programme" ressemblera Ă  (sous la plateforme POSIX unix / linux)

import os

def main():
      manager = multiprocessing.Manager()

# this is equivalent to "(cmd )&" under bash
pid = os.fork()
if pid == 0:
    cpid = os.fork()
    if cpid == 0:
        main()
    else:
        exit(0)
else:
    os.wait(pid)

Gardez à l'esprit que la gestion du processeur échappe à la portée du céleri, ce qui va un peu à l'encontre de l'idée d'utiliser le céleri, mais étant donné que vous alliez utiliser le multitraitement, vous voudrez probablement gérer l'utilisation du processeur en dehors du céleri de toute façon.

À tout le moins, cette limitation devrait ĂȘtre documentĂ©e. J'ai regardĂ© autour de moi dans le document et je n'ai pas trouvĂ©.

Encore une fois, n'hésitez pas à soumettre une demande d'extraction avec les modifications de la documentation.

suivi @martinth de commentaire sur Python 3.5.2, 4.0.0 et CĂ©leri billard 3.5.0 sa solution n'a pas fonctionnĂ©, comme les contrĂŽles de multitraitement sur le processus en cours daemon et il arrĂȘte de dĂ©marrer un enfant.

J'ai pu lever la restriction en réinitialisant l'indicateur de démon du travailleur. Je suis à peu prÚs sûr que c'est une mauvaise idée, mais cela permet de démarrer le multiprocessing.Pools à partir d'une tùche de céleri.

@worker_process_init.connect
def fix_multiprocessing(**kwargs):
    # don't be a daemon, so we can create new subprocesses
    from multiprocessing import current_process
    current_process().daemon = False

Cela dit, IMHO Celery devrait ajouter une option documentée pour configurer s'il démarre les travailleurs en tant que démons. Remarque J'utilise du céleri dans une cosse k8, donc le céleri est démarré en tant que processus de premier plan en utilisant celery worker , et je n'ai vraiment pas besoin de travailleurs démonisés.

@miraculixx Le problÚme avec cette suggestion est que nous aurons plus de modes d'échec à gérer et plus de problÚmes à résoudre. Nous préférons les éviter.

Bien que l'utilisation du multitraitement échoue en combinaison avec le pool préfork, cela semble fonctionner lors de l'utilisation du pool solo. Donc, je suppose qu'une solution de contournement serait de faire apparaßtre plusieurs céleris avec le pool solo, au lieu d'un avec plusieurs enfants dans le pool prefork. Cela vous semble-t-il légitime? Bien sûr, de cette façon, certaines options telles que max-mem-per-child ne fonctionneront pas.

Je pense qu'il s'agit essentiellement d'un problĂšme de conception d'application. C'est une douleur particuliĂšre pour daemonic processes are not allowed to have children , car vous savez, vous avez atteint un point oĂč vous devez repenser l'ensemble de l'application. Mais c'est une limitation au niveau du systĂšme d'exploitation, vous ne pouvez pas la contourner sans effets secondaires graves. Les processus dĂ©moniaques ne peuvent pas non plus avoir d'enfants en C. Ce n'est pas un truc spĂ©cifique Ă  Python. Il y avait autrefois un dĂ©bat sur les performances des threads et des processus, et en conclusion, aucun d'entre eux n'est significativement meilleur ou pire que l'autre.

Je suggÚre deux options (et en parlant en général, pas de céleri ici)

  • Utilisez subprocess.Popen pour gĂ©nĂ©rer un processus indĂ©pendant, qui peut avoir des enfants et utiliser des sockets UNIX pour la communication inter-processus
  • Est-il vraiment nĂ©cessaire que les threads soient gĂ©nĂ©rĂ©s par un processus fourchu et non par votre processus principal?

Pour ce que cela vaut, mon cas d'utilisation à l'époque était que je voulais lancer un sous-processus de longue durée qui se plantait souvent rapidement en raison de problÚmes d'entrée non triviaux (et non sensibles à la sécurité). L'idée était donc au moins de s'assurer que le processus se lance avec succÚs.

Il s'est avéré à long terme une conception médiocre pour diverses raisons, de sorte que la nouvelle architecture est naturellement revenue à l'utilisation «naturelle» des céleris asynchrones. Je suis donc d'accord avec l'idée de se demander si la fourche est vraiment nécessaire; la tùche est la fourchette.

pour ce que ça vaut, mon cas d'utilisation Ă©tait de lancer des processus scikit-learn qui utilisent le multitraitement (via joblib). J'ai depuis dĂ©veloppĂ© un backend de cĂ©leri vers joblib, ce qui signifie que scikit-learn lance des processus parallĂšles utilisant du cĂ©leri et que mon hack ci-dessus n'est plus nĂ©cessaire. Ceci est dans une Ă©tape POC, pas encore prĂȘt pour les heures de grande Ă©coute.

@miraculixx Avez-vous cela hĂ©bergĂ© quelque part? J'aimerais y jeter un Ɠil et / ou l'essayer. Je rencontre le mĂȘme problĂšme que vous - sklearn engendrant des sous-processus - et j'ai pratiquement abandonnĂ© le cĂ©leri.

@pgeez Si vous ne vous souciez pas de l'utilisation de sous-processus dans sklearn, vous pouvez définir la variable d'environnement JOBLIB_MULTIPROCESSING = 0. Voir https://github.com/scikit-learn/scikit-learn/blob/0.18.X/sklearn/externals/joblib/_multiprocessing_helpers.py

@jennaliu merci pour cette réflexion, mais comme @miraculixx , j'ai besoin d'

Avez-vous essayé la vieille astuce Unix à double fourchette pour désavouer les enfants du processus démon du céleri?

Avez-vous lu le titre de ce fil?!?!?

@sebastroy Ă©videmment, je suis ce fil depuis des annĂ©es. Je viens de dĂ©couvrir la double fourchette, mais je vois maintenant que ma confusion Ă©tait de penser que les fourchettes de dĂ©mon Ă©taient tuĂ©es par du cĂ©leri, pas qu'elles Ă©taient carrĂ©ment empĂȘchĂ©es.

Je t'ai eu. Ouais dans ma vie précédente, j'utilisais du C donc c'était comme du pain et du beurre.

La solution de contournement que j'utilise est subprocess.Popen qui fonctionne bien, mais vous devez ensuite réimplémenter une certaine logique (et créer une version shell du programme), c'est ce que le céleri devrait faire en premier lieu. Mais je l'ai corrigé en modifiant le comportement de l'implémentation de l'API de niveau supérieur. Je pense que c'est plus conforme au but du céleri. Simplifiez aussi une certaine logique que le bas niveau.

Heureusement, je trouve ce problÚme lorsque j'essaie d'exécuter un playbook ansible dans la tùche Celery.
La méthode fournie par @martinth n'a pas fonctionné pour moi. J'imprime le current_process()._config et j'obtiens
{'authkey': b"y&e\x8d'\xcb\xd4\r\xd2\x86\x06\xe7\x9e\x14\xaf \xbc\xc4\x95\xa5G\xec&[i\x19\xf3G-\x06\xac\x19", 'semprefix': '/mp', 'daemon': True} .
Ensuite, je réaffecte le champ daemon à False , et cela fonctionne.

Existe-t-il des solutions ou d'autres implémentations pour permettre l'exécution de multiprocessus dans la tùche?

@HeartUnchange : récemment, nous travaillons dur sur un projet Big Data, que nous souhaitons utiliser le céleri comme composant distribué. et avec votre guide, nous sommes trÚs chanceux de résoudre le problÚme. voir la configuration de la tùche:

     @app.task
    def handleBigZipfile(filename,nid):
    current_process()._config['daemon'] = False
    logger.info('{} begin handle!'.format(filename))
    handleAll(filename,nid)
     logger.info('{} is done!'.format(filename))

La solution est ok! nous commençons le projet à 2017.1 et maintenant le prototype est terminé! neuf mois se sont écoulés! Je vous remercie! et mes remerciements sont au-delà de l'expression!
pourriez-vous décrire plus en détail comment vous résolvez le problÚme! nous avons hùte de le savoir!

Salut ,

J'ai une configuration assez standard: Django + Rabbitmq + celery-4.0.2 + python-2.7 + centOS-7

J'essaie de créer un processus en utilisant le module multiprocesseur standard de python dans le céleri.

Les processus démons ne sont pas autorisés à créer des processus enfants et, par conséquent, les tùches qui utilisent un package multiprocesseur ne fonctionnent pas:
Commande utilisée pour exécuter: céleri worker -B -A celery_task -l debug
Journaux de suivi:

[2017-09-26 23:27:08,838: WARNING/PoolWorker-2] ERROR
[2017-09-26 23:27:08,839: WARNING/PoolWorker-2] Traceback (most recent call last):
[2017-09-26 23:27:08,839: WARNING/PoolWorker-2] File "/home/induser/config.py", line 612, in main
[2017-09-26 23:27:08,840: WARNING/PoolWorker-2] mylog_process = mp.Process(target=test_logger_process, args=(myqueue,))
[2017-09-26 23:27:08,840: WARNING/PoolWorker-2] File "/usr/lib64/python2.7/multiprocessing/process.py", line 98, in __init__
[2017-09-26 23:27:08,841: WARNING/PoolWorker-2] self._authkey = _current_process._authkey
[2017-09-26 23:27:08,841: WARNING/PoolWorker-2] AttributeError: 'Process' object has no attribute '_authkey'

Quelle pourrait ĂȘtre la raison de ne pas engendrer le processus?
Voici le code:

import multiprocessing as mp
from celery.schedules import crontab
from celery.decorators import periodic_task

@periodic_task(run_every=crontab(minute='*/1'), name='test_process_celery')
def main():
data = config_read()
try:
    myqueue = mp.Queue(-1)
    mylog_process = mp.Process(target=test_logger_process, args=(myqueue,))
    mylog_process.start()
    . . .
    . . .
except Exception as e:
    raise
finally:
    mylog_process.join()

Merci.

essayez master et signalez si c'est toujours le problĂšme

Il a toujours l'erreur. J'ai essayé d'utiliser un sous-processus avec:

from multiprocessing import Process, Value
import ctypes

[...]
        result = Value('i', 0)
        text = Value(ctypes.c_char_p, fail_string.encode())
        p = Process(target=reader.find_text_async, args=(result, text, ))
        p.start()
        p.join(5)

        if p.is_alive():
            logging.WARNING("Manual terminating the process 'find_text_async'")
            p.terminate()

mais avec la branche principale de céleri ça sais:

Fichier "/usr/lib/python3.5/multiprocessing/process.py", ligne 103, au début
'Les processus démoniaques ne sont pas autorisés à avoir des enfants'
AssertionError: les processus démoniaques ne sont pas autorisés à avoir des enfants

ÉDITER

J'ai changé le multitraitement avec le billard et ça marche!

from billiard import Process, Value

Cette page vous a été utile?
0 / 5 - 0 notes