Celery: Aufgaben dürfen keine Unterprozesse starten

Erstellt am 29. Nov. 2013  ·  68Kommentare  ·  Quelle: celery/celery

Ab Celery 3.1.0 verwendet der Prozesspool ( celery.concurrency.prefork , früher celery.concurrency.processes ) Daemon-Prozesse, um Aufgaben auszuführen.

Daemon-Prozesse dürfen keine untergeordneten Prozesse erstellen. Daher funktionieren Aufgaben, die das Paket multiprocessing , nicht:

[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

Hilfreichster Kommentar

@thedrow
Du hast das falsch verstanden. Zweimal.
Wir befürchten nicht, dass Sie nicht über die Ressource verfügen (dies ist vollkommen verständlich und leider ein sehr häufiger Fall bei freier Software). Wir sind besorgt, dass das Ticket aus diesem Grund geschlossen ist. So funktionieren Tickets nicht.
Wir sind nicht "unglücklich", wir sind schockiert.

Alle 68 Kommentare

Dies hat sich zwischen 3.0 und 3.1 nicht geändert, daher bin ich mir nicht sicher, warum Sie diesen Fehler jetzt und nicht vorher erhalten würden.

So kann dieser Fehler reproduziert werden.

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()

Ich führe Worker mit dem folgenden Befehl aus: celery worker -A app.app -l debug .

Mit Sellerie 3.0.24 gelingt die Aufgabe:

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

Mit Sellerie 3.1.5 funktioniert es nicht:

[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',)

Mein Verständnis des Problems ist das folgende: celery.concurrency.prefork.TaskPool verwendet celery.concurrency.asynpool.AsynPool ; AsynPool erbt von billiard.pool.Pool wodurch Daemon-Worker-Prozesse erzeugt werden, und AsynPool überschreibt dieses Verhalten nicht. Aber du hast recht, dieses Schema scheint nicht zwischen 3.0 und 3.1 geändert zu werden, also bin ich auch verwirrt :)

Und es scheint, dass ich mit diesem Problem nicht allein bin: http://stackoverflow.com/questions/20149421/threads-in-celery-3-1-5

Ein Unterschied besteht darin, dass der Arbeitsprozess jetzt eine Unterklasse von 'Prozess' ist, in der zuvor das Funktionsargument verwendet wurde: Process(target=) , möglicherweise gibt es einen Unterschied in den Standardwerten für diese Ansätze.

Multiprocessing und alte Versionen von Billard-Sets daemon=True :
https://github.com/celery/billiard/blob/2.7/billiard/pool.py#L904

Und so ist es auch in der neuesten Version:
https://github.com/celery/billiard/blob/3.3/billiard/pool.py#L1039

Ich denke, dass der Task-Prozess als Daemon eine ernsthafte Einschränkung für die Implementierung von Tasks darstellt.
Ich habe eine Aufgabe geschrieben, die Multiprocessing verwendet, um CPU-gebundene Operationen zu beschleunigen. Alles funktioniert gut, wenn ich einen Arbeiter in einem Terminal wie folgt starte:

Sellerie-Arbeiter --app = Aufgaben -Q wb -l info --concurrency = 1

Wenn ich jedoch ein Celeryd-Skript verwende, um einen Worker zu starten, wird folgende Ausnahme angezeigt:
AssertionError: Dämonische Prozesse dürfen keine Kinder haben

Ich fand heraus, was die Änderung des Verhaltens verursachte.
Aufgaben werden mit Daemon-Prozessen sowohl in 3.0 als auch in 3.1 ausgeführt, aber bis Sellerie / Billard @ 4c32d2e und https://github.com/celery/billiard/commit/c676b94aa4144349b11ab31c82296a5d804909c9 multiprocessing Modul war sich dessen nicht bewusst erlaubte das Erstellen von Unterprozessen.

Nach meinem Verständnis gab es vor Version 3.1 einen Fehler (Aufgaben durften Unterprozesse erstellen, die zu einem verwaisten Zustand führen konnten), und jetzt wurde dieser Fehler behoben.

Die Entscheidung, Python-Daemon-Prozesse nicht zu verzweigen, erscheint mir eher willkürlich. Obwohl ich den guten Glauben daran erkenne, habe ich das Gefühl, dass ich in der Lage sein sollte, die volle Kontrolle über dieses Verhalten zu haben, wenn ich mich dazu entscheide.

An einen Prozess pro Aufgabe gebunden zu sein, scheint mir eine ernsthafte Einschränkung zu sein. Gedanken?

Ich frage mich, warum diese Einschränkung überhaupt vorhanden ist. Eine Warnung, die ich verstehen kann, die ich jedoch völlig ablehne, erscheint albern, wenn Sie Prozesse mit anderen Mitteln perfekt abspalten können.

@ask , wäre das möglich, den Sellerie-Worker-Prozess mit dem Daemon-Flag False zu initialisieren? Oder konfigurierbar machen?

@ilyastam scheint, wir haben zur gleichen Zeit kommentiert

Ich stimme zu, dass dies eine willkürliche Einschränkung zu sein scheint, aber ich wünschte, ich wüsste überhaupt die Gründe für das Hinzufügen.

Dies ist eine bekannte Falle in Posix-Systemen, aber es ist immer noch erlaubt. Sie können untergeordnete Prozesse in einem Signalhandler bereinigen, dies schützt Sie jedoch nicht vor SIGKILL.

Ich denke, wir sollten die Beschränkung vom Billard entfernen, auch wenn dies vom Multiprozessor-Verhalten abweichen würde. Sie können weiterhin untergeordnete Prozesse mit dem Modul subpocess oder mit dem Aufruf fork niedriger Ebene erstellen, sodass Hauptbenutzer in der Lage sein sollten, untergeordnete billiard.Process Instanzen zu erstellen.

@ilyastam Sollte in der Lage sein, die Raise-Anweisung zu entfernen, müssen Sie die Prozesse nicht "Nicht-Daemon" machen.

Das heißt, Daemon-Prozesse können untergeordnete Prozesse erstellen, auch wenn sie diese nicht ernten können.
So funktioniert posix sowieso.

Übrigens, beachten Sie, dass dies keine raise , sondern eine Assert-Anweisung, die entfernt wird, wenn Python mit dem Argument PYTHONOPTIMIZE envvar oder -O gestartet wird.

Billard 3.3.0.11 ist auf PyPI einschließlich dieser Änderung

@ask danke. Irgendeine Idee, welche Sellerieversion diese Verbesserung sehen wird?

multiprocessing Dokumentation zu ausdrücklich angegeben, dass der Daemon-Prozess keine Unterprozesse erstellen darf, und es wird erläutert, warum. Für mich sieht diese assert -Anweisung eher so aus, als wäre sie hier als Abkürzung für raise (das machen die Leute oft).

Diese Einschränkung ist dokumentiert und ich denke nicht, dass es für Sellerie eine gute Idee ist, multiprocessing stillschweigend mit Affen zu patchen und wegzunehmen. Dies könnte zu wirklich unerwarteten und schädlichen Folgen führen.

Ich kann mir das folgende Beispiel vorstellen (es scheint jedoch ein bisschen erfunden zu sein):

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

Dieser Code wird als einfache Python-Funktion ausgeführt und funktioniert ordnungsgemäß. Wenn es jedoch als Sellerie-Aufgabe ausgeführt wird (mit Sellerie Version 3.0. *), Bleiben drei Unterprozesse übrig, die für immer hängen bleiben. Wenn der Sellerie-Arbeiter beendet wird, werden diese Unterprozesse verwaist.

Es erklärt nicht warum, es gibt nur das Unix-Verhalten an, das Sie beim Starten eines Kind-Kind-Prozesses erwarten würden. Obwohl es eine berüchtigte Einschränkung in Unix ist, hindert es die Leute nicht daran, es zu tun. Das ist nicht anders als
Starten eines subprocess.Popen -Prozesses oder Aufrufen von fork() , um einen neuen Prozess zu starten. Warum sollte es also illegal sein?

So machen Sie Ihr Beispiel:

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()

Um dies zu töten (-9), müssten Sie auch -9 die untergeordneten Prozesse töten, aber das ist etwas, was Sie haben werden
für alle Unix-Prozesse zu berücksichtigen.

Nicht, dass ich die Erstellung eines Pools für jede Aufgabe befürworte, aber ich verstehe nicht, warum Benutzer, die wissen, was sie sind
Dabei sollte es nicht erlaubt sein, Prozesse von einer Aufgabe aus zu starten.

Außerdem flicken wir nichts mit Affen. Dies ist nur eine Änderung des Billard.

Außerdem flicken wir nichts mit Affen. Dies ist nur eine Änderung des Billard.

Mit "Affen-Patching" meine ich diese Zuweisung, die multiprocessing._current_process durch eine Instanz von billiard.process.Process : https://github.com/celery/billiard/blob/master/billiard/process.py # L53.

Ich bin damit einverstanden, dass es nichts Falsches ist, Kind-Kind-Prozesse zu starten, wenn sie richtig gehandhabt werden (wie in Ihrem Beispiel). Mein Punkt ist, dass multiprocessing nicht so geschrieben ist und wir die Einschränkungen der Implementierung nicht ignorieren sollten.

@aromanovich Es kann nicht anders geschrieben werden, es ist keine Einschränkung der Mehrfachverarbeitung, es ist eine Einschränkung des Unix.

Es setzt _current_process so, dass die Formatvariable processName der Protokollierungsmodule funktioniert und das Billard-Prozessobjekt dieselbe API wie das Multiprocessing-Prozessobjekt hat, sodass der aktuelle Prozess sicher festgelegt werden kann.

Übrigens müssten Sie Billard verwenden, um die Begrenzung aufzuheben. Die Verwendung von Multiprocessing löst immer noch die Ausnahme aus.

Könnte dieses Problem auch mit diesem Ansatz beheben:
http://stackoverflow.com/questions/6974695/python-process-pool-non-daemonic
Dadurch können Benutzer das Multiprocessing-Modul weiterhin verwenden und dieses Problem vermeiden:
https://github.com/celery/billiard/issues/99

Ich erhalte diesen Fehler, wenn ich eine @ parallel Fabric-Aufgabe innerhalb einer Sellerie-Aufgabe

@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 verwenden ENV
export PYTHONOPTIMIZE = 1
um diese Behauptung zu entfernen. Sie müssen alle Dinge erledigen.

@xiaods Ich glaube, ich habe dieses Problem mit so etwas gelöst:

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

Problem

Ich habe eine Aufgabe, die einige Daten berechnet und einen Scikit-Lernklassifikator lädt, um basierend auf diesen Daten Vorhersagen zu treffen. Wenn ich die Aufgabe selbst ausführe, ist alles in Ordnung, aber wenn ich sie mit Sellerie ausführe, wird eine Fehlermeldung angezeigt, wenn die Aufgabe versucht, den eingelegten Klassifikator zu laden:

[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'

Fortpflanzen

Erstellen Sie einen leeren Klassifikator und speichern Sie ihn als Gurke:

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

Erstellen Sie eine einfache App ( 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)

Starten Sie den Sellerie-Arbeiter:

celery -A app worker --loglevel=debug

Führen Sie die App aus:

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

Fehlermeldung:

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

Lösung

Ich denke, es sollte eine Option zum "Monkeypatch" von Sellerie geben, damit Aufgaben Unterprozesse starten können, insbesondere wenn es in der Vergangenheit eine solche "Funktion" gab. Im Moment wechseln die Benutzer einfach zu anderen Frameworks, wenn sie auf dieses Problem stoßen: http://stackoverflow.com/questions/27904162/using-multiprocessing-pool-from-celery-task-raises-exception. Hier ist ein weiteres Beispiel für diesen Fehler: http://stackoverflow.com/questions/22674950/python-multiprocessing-job-to-celery-task-but-attributeerror.

Diese Ausgabe sollte erneut geöffnet werden ...

Ich bin gerade auf das gleiche Problem gestoßen. Ich verwende nltk in einem meiner Mitarbeiter, der wiederum scikit-learn importiert, was zu demselben Fehler führt, den @ostrokach angezeigt hat .

Es scheint, dass ich dies mit dem folgenden Code umgehen kann:

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'}

Dies ist offensichtlich ein sehr grober Hack und ich weiß nicht, was passieren würde, wenn ich wirklich Multiprocessing verwenden würde (zum Teufel weiß ich nicht einmal, was semprefix ist), aber es reicht aus, um scikit-learn wieder arbeiten.

Ich lasse dies hier für andere Leute, die über das gleiche Problem stolpern, bis dieses Problem behoben ist.

Könnte dies eine Art Inkompatibilität mit Billard unter Python 3 sein? Oder ist es auch auf Python 2 reproduzierbar?

Ist das ursprüngliche Problem, dass Sellerieprozesse keine Unterprozesse erstellen können, immer noch ein Problem? Rückblickend wurde es mit Sellerie / Billard @ e6bb0f7 für Version 3.3

@martinth Danke, dieser Hack funktioniert auch bei mir!

@ Xiaods Danke! Ihre Lösung funktioniert bei mir! Vielen Dank!

@ Gilinson es ist immer noch ein Problem und Export PYTHONOPTIMIZE = 1 "behebt" es immer noch.
Ich bin gerade auf dasselbe Problem gestoßen und habe versucht, ein ansibles Playbook in der Sellerie-Aufgabe auszuführen

@martinth Danke für den Hack! Ich habe das gleiche Problem mit:

  • Python 3.4.3
  • Sellerie == 3.1.18
  • scikit-learn == 0.17

Der Hack von gestoßen , Multiprocessing zu verwenden, um einige Berechnungen zu beschleunigen. Verwendete stattdessen das Threading-Modul und es scheint diesen Fehler für mich zu beheben, während meine Verarbeitung immer noch unterbrochen wird.

Die Verwendung der thread-basierten multiprocessing.dummy hat bei mir in Sellerie funktioniert:

from multiprocessing.dummy import Pool

Dieser Fehler tritt auch in Python 2.7.5 weiterhin auf. Ich bin mir nicht sicher, ob es jemals beabsichtigt ist, es anzusprechen, aber dies macht die Verwendung von Saltstacks Salt-SSH für Sellerie nicht verwendbar.

Schließen Sie dies, da wir nicht über die Ressourcen verfügen, um diese Aufgabe abzuschließen.

Mögliche Lösung"

Ich hatte eine solche Aufgabe, bei der versucht wurde, Threads zu erstellen, und dies würde fehlschlagen. Ich habe es geschafft, dass es funktioniert, indem ich zu einem Bash-Skript gegabelt habe, das selbst zu einem Python-Interpreter führt, der genau denselben Code ausführt (und daher Threads erstellen konnte, was für meinen Anwendungsfall kritisch war).

Ich verstehe nicht, warum das Ticket geschlossen ist. Wenn Sie keine Ressource dafür haben, können Sie einen Kommentar dazu abgeben, aber das Ticket wird dadurch nicht geschlossen. Sie verstecken nur den Fehler dabei.

Was besonders schlecht für ein Ticket ist, das sowohl für die Priorität als auch für den Schweregrad als "kritisch" gekennzeichnet ist.

@orzel +1.
Priorität: Kritisch
Schweregrad: Kritisch
Schließen Sie dies, da wir nicht über die Ressourcen verfügen, um diese Aufgabe abzuschließen.

Das ist ein Witz. Wenn Sie jetzt keine Ressourcen haben, beheben Sie diese jetzt nicht. Beheben Sie das Problem, wenn Sie über Ressourcen verfügen. Durch das Schließen des Tickets wird das Problem nicht behoben

@orzel @Templarrr Ich habe dieses Ticket als kritisch gekennzeichnet, damit @ask hier nicht schuld ist.
Sie mögen darüber unglücklich sein, aber Protest hilft nicht weiter.
Wir müssen unseren Rückstand darauf aufbauen, was umsetzbar ist und was nicht und derzeit nicht.
Es ist ein schwieriger Anruf, aber jemand muss ihn tätigen.
Wenn Ihnen dieses Problem im Weg steht, versuchen Sie es zu beheben. Ich verspreche, wenn das Update korrekt ist und die entsprechenden Tests hat, werde ich es zusammenführen.

@thedrow
Du hast das falsch verstanden. Zweimal.
Wir befürchten nicht, dass Sie nicht über die Ressource verfügen (dies ist vollkommen verständlich und leider ein sehr häufiger Fall bei freier Software). Wir sind besorgt, dass das Ticket aus diesem Grund geschlossen ist. So funktionieren Tickets nicht.
Wir sind nicht "unglücklich", wir sind schockiert.

Ich bin auch völlig anderer Meinung, dies zu schließen.

Ich denke, wir können uns alle einig sein, dass dies tatsächlich ein Fehler ist. Und obwohl es in der Tat traurig ist, dass es nicht genügend Ressourcen gibt, um einen _definiten_ Fehler zu schließen, hilft dies nicht weiter. Sie können unmöglich wissen, ob vielleicht morgen jemand lange kommt und denkt "Lasst uns einige Fehler in Sellerie beheben", nur um die offenen Probleme durchzusehen und denkt "Nun, hier gibt es keine interessante Arbeit zu erledigen ... lasst uns arbeiten auf _OtherProject_ statt ".
Wenn Sie dieses Problem schließen, wird es außerdem schwieriger, es zu finden. Ich weiß nicht, wie Sie Github verwenden, aber wenn ich ein potenzielles Problem entdecke, suche ich zuerst im Issue-Tracker nach offenen Problemen. Im Allgemeinen wird viel diskutiert und mehr noch nie gibt es auch eine Problemumgehung (wie in diesem Fall), die ich vorerst verwenden kann. Nur wenn ich wirklich verzweifelt bin, beginne ich, die geschlossenen Fragen durchzusehen.

Dies ist kein "Backlog Grooming", sondern eine Nummernoptimierung. Wenn ich mir die zu verwendenden Dinge anschaue, schaue ich mir die Anzahl der offenen Ausgaben an, aber ich schaue auch immer die Anzahl der Sterne an (was für Sellerie ziemlich hoch ist). Ich verstehe, dass es wünschenswert ist, eine geringe Anzahl von Fehlern zu haben, um die Öffentlichkeit anzusprechen, aber auch um Ihrer selbst willen. Ehrlich gesagt verstehe ich, dass es keine schöne Zahl ist, "250 offene Ausgaben" zu sehen, und das klingt überwältigend.

Wenn Sie nicht die Arbeitskräfte haben, um im nächsten Monat (oder sogar im nächsten Jahr) daran zu arbeiten, ist dies in Ordnung. Nur nicht schließen. Ein Abschluss sollte nur erfolgen, wenn das Problem entweder behoben ist oder absolut klar ist, dass es niemals ausgeführt wird. Beides ist hier nicht der Fall.

Entfernen Sie einfach die "Kritisch" -Flaggen und fügen Sie ein "Verschoben" -Flag für alles hinzu, was jetzt nicht behandelt werden kann, aber behandelt werden sollte, wenn die Ressource _ verfügbar ist.

Ich bin nicht sicher, ob wir das Problem tatsächlich beheben können. Wir können die Funktionsweise von Unix nicht ändern, aber wir könnten einen Patch stromaufwärts einreichen, um die Einschränkung aufzuheben.

Vielleicht gibt es plattformspezifische Lösungen unter Linux, aber das müsste untersucht werden. Es ist seit 2 Jahren geöffnet, ohne dass jemand den Anreiz hat, es zu reparieren, daher ist es unwahrscheinlich, dass es in der Near-Funktion repariert wird.

Ich habe mehr als 200 Ausgaben geschlossen und weit über 30.000 E-Mails als gelesen markiert, sodass einige davon zwangsläufig umstritten sind und wir diese möglicherweise erneut öffnen müssen. Ich erwarte das völlig, aber dann wäre es schön, wenn wir auch zu einer Lösung beitragen könnten, z. B. indem wir helfen, den Defekt zu dokumentieren, wenn dies die einzige bekannte Option ist.

Wir sind voller Arbeit und versuchen, ein riesiges Projekt ohne Ressourcen zu betreiben. Wir können keine Probleme untersuchen oder herausfinden, welche Probleme bereits behoben wurden.

Na ja ... okay. Aber könnte zumindest die Tatsache dokumentiert werden, dass "Sie Multiprocessing nicht verwenden können, wenn Sie Code für einen Sellerie-Arbeiter schreiben"? Ich meine ... es wird immer Leute geben, die es nicht lesen, aber zumindest können Sie darauf zeigen und sagen: "Sehen Sie, es ist dokumentiert. Wir können es nicht ändern. Beschäftigen Sie sich damit."

Meine Aufgabenliste ist gigantisch. Sie können die Dokumentation jetzt direkt auf github bearbeiten, sodass es wirklich einfach ist, Änderungen wie diese beizutragen :(

Ich mache das nicht, um Probleme zu verbergen, ich mache das, um Leute zum Handeln zu bewegen, gerade weil ich möchte, dass es verbessert wird.

@ask Können wir Multiprocessing innerhalb einer Aufgabe mit Sellerie in Django anwenden?
Gibt es dafür eine Alternative?

@abhisheksachan Sie sollten diese ganze Ausgabe lesen, bevor Sie eine solche Frage stellen

@abhisheksachan Ich habe dies seit einigen Jahren nicht mehr versucht, aber ich hatte es mit https://pypi.python.org/pypi/billiard zum Laufen gebracht , weil es die Dämonisierung von Unterprozessen ermöglicht.

Ja, Sie müssen Importe aus 'Multiprocessing' durch 'Billard' ersetzen, zum Beispiel:

from multiprocessing import Process

->

from billiard import Process

Es gibt keine Möglichkeit für uns, die Multiprozessor-Beschränkung zu deaktivieren, aber wir argumentieren, dass es sowieso keine Beschränkung geben sollte, sodass unsere Multiprocessing-Gabel dies zulässt.

Für alle, die wie ich in die Entwicklung eines Warteschlangensystems investiert haben, bevor sie diese Einschränkung herausgefunden haben und eine andere Problemumgehung benötigen, bis sie zu einem benutzerfreundlicheren rabbitMQ-Python-Wrapper migrieren können, habe ich es geschafft, das Problem zu umgehen, indem ich einen externen Unterprozess aufgerufen habe, der dies kann Gabel selbst sauber. Dieser gegabelte Prozess befindet sich jetzt außerhalb des Sellerie-Sandkastens und die Dinge funktionieren so, wie sie sollten.

Ersetzen Sie im OP-Beispiel:

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

mit:

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

und das "Programm" wird aussehen wie (unter POSIX Unix / Linux-Plattform)

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)

Denken Sie daran, dass das CPU-Management dem Umfang des Selleries entgeht, was der Idee der Verwendung von Sellerie widerspricht. Angesichts der Tatsache, dass Sie Multiprocessing verwenden würden, möchten Sie die CPU-Auslastung wahrscheinlich trotzdem außerhalb des Selleries handhaben.

Zumindest sollte diese Einschränkung dokumentiert werden. Ich sah mich im Dokument um und konnte es nicht finden.

Sie können auch hier eine Pull-Anfrage mit den Dokumentationsänderungen senden.

Nach dem Kommentar von @martinth zu Python 3.5.2, Celery 4.0.0 und Billard 3.5.0 funktionierte seine Lösung nicht, da die Mehrfachverarbeitung den zu dämonisierenden Prozess überprüft und verhindert, dass ein Kind gestartet wird.

Ich konnte die Einschränkung aufheben, indem ich das Daemon-Flag des Arbeiters zurücksetzte. Ich bin mir ziemlich sicher, dass dies eine schlechte Idee ist, aber es ermöglicht das Starten von Multiprocessing.Pools aus einer Sellerie-Aufgabe heraus.

@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

IMHO Celery sollte jedoch eine dokumentierte Option hinzufügen, um zu konfigurieren, ob Arbeiter als Deamons gestartet werden. Hinweis: Ich verwende Sellerie in einem k8-Pod, sodass Sellerie als Vordergrundprozess mit celery worker gestartet wird, und ich brauche wirklich keine dämonisierten Arbeiter.

@miraculixx Das Problem mit diesem Vorschlag ist, dass wir mehr

Obwohl die Verwendung von Multiprocessing in Kombination mit dem Prefork-Pool fehlschlägt, scheint dies bei Verwendung des Solo-Pools zu funktionieren. Ich denke also, eine Problemumgehung wäre, mehrere Sellerie-Arbeiter mit dem Solo-Pool zu spawnen, anstatt einen mit mehreren Kindern im Prefork-Pool. Klingt das echt? Natürlich funktionieren auf diese Weise einige Optionen wie max-mem-per-child nicht.

Ich denke, dies ist im Grunde ein Problem beim Anwendungsdesign. Es ist ein besonderer Schmerz für daemonic processes are not allowed to have children , weil Sie wissen, dass Sie einen Punkt erreicht haben, an dem Sie die gesamte Anwendung neu gestalten müssen. Es handelt sich jedoch um eine Einschränkung des Betriebssystems. Sie können diese nicht ohne schwerwiegende Nebenwirkungen umgehen. Dämonische Prozesse können auch keine Kinder in C haben. Dies ist kein Python-spezifisches Zeug. Früher gab es eine Debatte über Thread- und Prozessleistung, und als Schlussfolgerung stellte sich heraus, dass keiner von ihnen signifikant besser oder schlechter ist als der andere.

Ich schlage zwei Optionen vor (und spreche im Allgemeinen nicht über Sellerie hier)

  • Verwenden Sie subprocess.Popen , um einen unabhängigen Prozess zu erzeugen, der untergeordnete Elemente haben kann, und verwenden Sie UNIX-Sockets für die Kommunikation zwischen Prozessen
  • Ist es wirklich notwendig, dass die Threads durch einen gegabelten Prozess erzeugt werden und nicht durch Ihren Hauptprozess?

Mein damaliger Anwendungsfall war, dass ich einen lang laufenden Unterprozess starten wollte, der aufgrund nicht trivialer (und nicht sicherheitsrelevanter) Eingabeprobleme häufig schnell abstürzte. Die Idee war also, zumindest sicherzustellen, dass der Prozess erfolgreich gestartet wurde.

Es stellte sich auf lange Sicht aus verschiedenen Gründen als schlechtes Design heraus, so dass die neue Architektur natürlich auf die "natürliche" Verwendung asynchroner Sellerie-Arbeiter zurückging. Ich stimme also der Idee zu, zu hinterfragen, ob das Gabeln wirklich notwendig ist. Die Aufgabe ist die Gabel.

Mein Anwendungsfall war es, Scikit-Lernprozesse zu starten, die Multiprocessing (über joblib) verwenden. Seitdem habe ich ein Sellerie-Backend für joblib entwickelt, was bedeutet, dass scikit-learn parallele Prozesse mit Sellerie startet und mein oben genannter Hack nicht mehr erforderlich ist. Dies befindet sich in einer POC-Phase und ist noch nicht für die Hauptsendezeit bereit.

@miraculixx Hast du das irgendwo gehostet? Ich würde gerne einen Blick darauf werfen und / oder es ausprobieren. Ich habe das gleiche Problem wie Sie - das Erlernen von Laich-Unterprozessen - und ich habe Sellerie im Grunde genommen aufgegeben.

@pgeez Wenn Sie die Verwendung von Unterprozessen in sklearn nicht interessieren, können Sie die Umgebungsvariable JOBLIB_MULTIPROCESSING = 0 setzen. Siehe https://github.com/scikit-learn/scikit-learn/blob/0.18.X/sklearn/externals/joblib/_multiprocessing_helpers.py

@ Jennaliu danke für den Gedanken, aber wie bei @miraculixx muss Multiprocessing aktiviert sein.

Habt ihr den alten Unix-Doppelgabel-Trick ausprobiert, um Kinder vom Daemon-Prozess des Selleries auszuschließen?

Hast du den Titel dieses Threads gelesen?!?!?

@sebastroy offensichtlich, ich Doppelgabel entdeckt, aber jetzt sehe ich meine Verwirrung darin, dass Dämonengabeln durch Sellerie getötet wurden, nicht dass sie direkt verhindert wurden.

Erwischt. Ja, in meinem vorherigen Leben habe ich C verwendet, also war das wie Brot und Butter.

Die Problemumgehung, die ich verwende, ist subprocess.Popen, was gut funktioniert, aber dann müssen Sie eine Logik neu implementieren (und eine Shell-Version des Programms erstellen), die Sellerie eigentlich tun sollte. Aber ich habe es behoben, indem ich das Verhalten der API-Implementierung der obersten Ebene geändert habe. Es ist eher auf den Zweck von Sellerie ausgerichtet, denke ich. Vereinfachen Sie auch einige Logik, die das niedrige Niveau.

Zum Glück , Ich finde dieses Problem, wenn ich versuche, ein ansible Playbook in der Sellerie-Aufgabe auszuführen.
Die von @martinth bereitgestellte current_process()._config und bekomme
{'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} .
Dann ordne ich das Feld daemon False , und es funktioniert.

Gibt es einige Lösungen oder andere Implementierungen, um das Ausführen von Multiprozessen in Aufgaben zu ermöglichen?

@HeartUnchange : intensiv an einem Big-Data-Projekt, bei dem wir Sellerie als verteilte Komponente verwenden möchten. und mit Ihrem Führer sind wir so glücklich, das Problem zu lösen. Siehe die Aufgabenkonfiguration:

     @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))

Die Lösung ist ok! Wir beginnen das Projekt um 2017.1 und jetzt ist der Prototyp fertig! Neun Monate sind vergangen! Ich danke dir! und mein Dank ist unaussprechlich!
Würden Sie bitte mehr darüber beschreiben, wie Sie das Problem herausfinden? das wollen wir unbedingt wissen!

Hallo ,

Ich habe ein ziemlich normales Setup: Django + Rabbitmq + Sellerie-4.0.2 + Python-2.7 + CentOS-7

Ich versuche, einen Prozess mit dem Standard-Python-Multiprocessing-Modul in Sellerie zu erzeugen.

Daemon-Prozesse dürfen keine untergeordneten Prozesse erstellen. Daher funktionieren Aufgaben, die ein Multiprocessing-Paket verwenden, nicht:
Befehl zum Ausführen: Sellerie-Arbeiter -B-A Sellerie_Aufgabe -l Debug
Traceback-Protokolle:

[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'

Was könnte der Grund dafür sein, dass der Prozess nicht ausgelöst wird?
Hier ist der 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()

Danke.

Versuchen Sie es mit Master und melden Sie, wenn es immer noch das Problem ist

Es hat immer noch den Fehler. Ich habe versucht, einen Unterprozess zu verwenden mit:

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()

aber mit Sellerie Master Branch sagt es:

Datei "/usr/lib/python3.5/multiprocessing/process.py", Zeile 103, am Start
"Dämonische Prozesse dürfen keine Kinder haben"
AssertionError: Dämonische Prozesse dürfen keine Kinder haben

BEARBEITEN

Ich habe Multiprocessing mit Billard geändert und es funktioniert!

from billiard import Process, Value

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen