Frage

Beim Benutzen Python-daemon, Ich erstelle Subprozesse Likeso:

import multiprocessing

class Worker(multiprocessing.Process):
   def __init__(self, queue):
      self.queue = queue # we wait for things from this in Worker.run()

   ...

q = multiprocessing.Queue()

with daemon.DaemonContext():
    for i in xrange(3):
       Worker(q)

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

Wenn ich den Elternprozess (dh kein Arbeiter) mit einem Strg-C oder Sigterm usw. töte, sterben die Kinder nicht. Wie tötet man die Kinder?

Mein erster Gedanke ist zu verwenden ATEXIT Um alle Arbeiter zu töten, Likeso:

 with daemon.DaemonContext():
    workers = list()
    for i in xrange(3):
       workers.append(Worker(q))

    @atexit.register
    def kill_the_children():
        for w in workers:
            w.terminate()

    while True: # let the Workers do their thing
       q.put(_something_we_wait_for())

Die Kinder von Daemons sind jedoch schwierige Dinge, und ich wäre für Gedanken und Eingaben, wie dies getan werden sollte, verpflichtet.

Vielen Dank.

War es hilfreich?

Lösung

Ihre Optionen sind etwas begrenzt. Wenn self.daemon = True im Konstruktor für die Worker Die Klasse löst Ihr Problem nicht und versucht, Signale im Elternteil zu fangen (dh,,, SIGTERM, SIGINT) funktioniert nicht, Sie müssen möglicherweise die entgegengesetzte Lösung ausprobieren. Anstatt die Eltern die Kinder zu töten, können Sie die Kinder bei sterben.

Der erste Schritt besteht darin, dem Konstruktor zu geben Worker das PID des übergeordneten Prozesss (Sie können dies mit tun os.getpid()). Dann, anstatt nur zu tun self.queue.get() Machen Sie in der Arbeiterschleife so etwas:

waiting = True
while waiting:
    # see if Parent is at home
    if os.getppid() != self.parentPID:
        # woe is me! My Parent has died!
        sys.exit() # or whatever you want to do to quit the Worker process
    try:
        # I picked the timeout randomly; use what works
        data = self.queue.get(block=False, timeout=0.1)
        waiting = False
    except queue.Queue.Empty:
        continue # try again
# now do stuff with data

Die obige Lösung überprüft, ob sich die Eltern -PID von der ursprünglich unterscheidet (dh, wenn der Kinderprozess von übernommen wurde von init oder lauchd Weil der Elternteil gestorben ist) - siehe Hinweis. Wenn das jedoch aus irgendeinem Grund nicht funktioniert, können Sie es durch die folgende Funktion ersetzen (angepasst von hier):

def parentIsAlive(self):
    try:
        # try to call Parent
        os.kill(self.parentPID, 0)
    except OSError:
        # *beeep* oh no! The phone's disconnected!
        return False
    else:
        # *ring* Hi mom!
        return True

Wenn der Elternteil nun stirbt (aus irgendeinem Grund), werden die Kinderarbeiter spontan wie Fliegen fallen - genau wie Sie wollten, Ihr Daemon! :-D

Andere Tipps

Kannst du nicht einfach die übergeordnete PID speichern, wenn das Kind zum ersten Mal erstellt wird (sagen wir in self.myppid) und wann self.myppid ist unterschiedlich von getppid() bedeutet, dass der Elternteil gestorben ist.

Sie können auch Signale verwenden, um zu vermeiden, dass sich weiterhin geändert hat, ob sich der Elternteil geändert hat. Ich kenne die Python -Einzelheiten nicht, aber etwas entlang, wie es beschrieben wird Hier (unten auf der Seite) könnte funktionieren.

Atexit wird den Trick nicht ausführen-es wird nur nach einer erfolgreichen nicht signalen Beendigung ausgeführt-siehe die Notiz oben in der Spitze der Dokumente. Sie müssen die Signalhandhabung über eine von zwei Mitteln einrichten.

Die einfachere Option: Setzen Sie das Dämon-Flag auf Ihren Arbeitsprozessen per Figur http://docs.python.org/library/multiprocessing.html#process-and-eceptions

Etwas härter klingende Option: PEP-3143 Es scheint zu implizieren, dass es einen integrierten Weg gibt, um das Programm in Python-Daemon zu säubern.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top