Frage

Gibt es eine Möglichkeit alle geschaffen subprocess, um sicherzustellen, sind tot an der Ausfahrt Zeit eines Programms Python? Durch subprocess meine ich diejenigen mit subprocess.Popen () erstellt wurde.

Wenn nicht, sollte ich iterieren alle die Ausgabe kills über und dann tötet -9? etwas sauberer?

War es hilfreich?

Lösung

Sie können mit atexit für diese, und registrieren jede aufzuräumen Aufgaben ausgeführt werden, wenn das Programm beendet wird.

atexit.register (func [* args [** Kargs]])

In Ihrem Bereinigungsprozess, können Sie auch Ihre eigene Warte implementieren, und es töten, wenn ein gewünschter Timeout auftritt.

>>> import atexit
>>> import sys
>>> import time
>>> 
>>> 
>>>
>>> def cleanup():
...     timeout_sec = 5
...     for p in all_processes: # list of your processes
...         p_sec = 0
...         for second in range(timeout_sec):
...             if p.poll() == None:
...                 time.sleep(1)
...                 p_sec += 1
...         if p_sec >= timeout_sec:
...             p.kill() # supported from python 2.6
...     print 'cleaned up!'
...
>>>
>>> atexit.register(cleanup)
>>>
>>> sys.exit()
cleaned up!

Hinweis -. Registrierte Funktionen werden nicht ausgeführt werden, wenn dieser Prozess (Eltern-Prozess) getötet wird,

Die folgende Fenster Methode wird nicht mehr benötigt für Python> = 2.6

Hier ist ein Weg, um einen Prozess in den Fenstern zu töten. Ihr Popen Objekt hat ein pid Attribut, so dass Sie es einfach anrufen können durch Erfolg = win_kill (p.pid) (Needs pywin32 installiert ist):

    def win_kill(pid):
        '''kill a process by specified PID in windows'''
        import win32api
        import win32con

        hProc = None
        try:
            hProc = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, pid)
            win32api.TerminateProcess(hProc, 0)
        except Exception:
            return False
        finally:
            if hProc != None:
                hProc.Close()

        return True

Andere Tipps

Auf * nichts ist, vielleicht Prozessgruppen verwenden, können Ihnen helfen, -. Sie Subprozesse gelaicht von Ihrem Subprozesse auch fangen können

if __name__ == "__main__":
  os.setpgrp() # create new process group, become its leader
  try:
    # some code
  finally:
    os.killpg(0, signal.SIGKILL) # kill all processes in my group

Eine weitere Überlegung ist, die Signale zu eskalieren: von SIGTERM (Standardsignal für kill) zu SIGKILL (a.k.a kill -9). Warten Sie eine kurze Zeit zwischen den Signalen dem Prozess eine Chance zu geben, sauber zu beenden, bevor Sie es kill -9.

Die subprocess.Popen.wait() ist der einzige Weg, um sicherzustellen, dass sie tot sind. Tatsächlich erfordern POSIX OS, dass Sie auf Ihre Kinder warten. Viele * nix ist ein „Zombie“ Prozess erstellen. Ein totes Kind, für die die Eltern nicht warten

Wenn das Kind einigermaßen gut geschrieben, es endet. Oft lesen Kinder von PIPE. der Eingang geschlossen ist ein großer Hinweis auf das Kind, dass es sollte den Laden und Ausgang schließen.

Wenn das Kind Fehler hat und nicht beendet, können Sie es töten. Sie sollen diese Fehler beheben.

Wenn das Kind eine „Serve-forever“ Schleife und ist nicht zu beenden, entworfen, sollten Sie entweder töten oder eine Eingabe oder eine Nachricht, die es zwingen werden, zu beenden.


Bearbeiten.

Im Standard-OS haben Sie os.kill( PID, 9 ). Kill -9 ist hart, BTW. Wenn man sie mit SIGABRT töten kann (6?) Oder SIGTERM (15), das ist höflicher.

In Windows OS, Sie keine os.kill haben, die funktioniert. Schauen Sie sich diese Activestate Rezept für einen Prozess in Windows beendet wird.

Wir haben untergeordnete Prozesse, die WSGI-Server sind. So beenden wir ihnen eine GET auf einer speziellen URL tun; Dies bewirkt, dass das Kind zu säubern und zu beenden.

Achtung: Linux-only! Sie können Ihr Kind erhält ein Signal, wenn seine Eltern sterben machen.

Erste Python-prctl == 1.5.0 dann Ihre Eltern Code ändern Sie Ihr Kind-Prozesse zu starten wie folgt

installieren
subprocess.Popen(["sleep", "100"], preexec_fn=lambda: prctl.set_pdeathsig(signal.SIGKILL))

Was dies sagt, ist:

  • Start subprocess: Schlaf 100
  • nach gabeln und vor exec des subprocess, das Kind für Register „schicken Sie mir ein SIGKILL wenn meine Eltern beendet“.
  

poll ()

     

Überprüfen Sie, ob Kind-Prozess beendet wurde.   Returns Return Attribut.

Ich brauchte eine kleine Variation dieses Problems (Subprozesse Aufräumen, aber ohne das Python-Programm selbst verläßt), und da es hier nicht unter den anderen Antworten erwähnt:

p=subprocess.Popen(your_command, preexec_fn=os.setsid)
os.killpg(os.getpgid(p.pid), 15)

setsid wird das Programm in einer neuen Sitzung ausgeführt werden, so dass eine neue Prozessgruppe sie und ihre Kinder zuweisen. Aufruf os.killpg an wird es also nicht, Ihren eigenen Python-Prozess bringt auch.

oriP Antwort ist hilfreich, hat aber den Nachteil, dass es Ihren Prozess tötet und gibt einen Fehlercode Ihre Eltern. Ich vermied es, dass wie folgt aus:

class CleanChildProcesses:
  def __enter__(self):
    os.setpgrp() # create new process group, become its leader
  def __exit__(self, type, value, traceback):
    try:
      os.killpg(0, signal.SIGINT) # kill all processes in my group
    except KeyboardInterrupt:
      # SIGINT is delievered to this process as well as the child processes.
      # Ignore it so that the existing exception, if any, is returned. This
      # leaves us with a clean exit code if there was no exception.
      pass

Und dann:

  with CleanChildProcesses():
    # Do your work here

Natürlich können Sie dies mit try / except / finally, aber Sie haben die außergewöhnlichen und nicht-Ausnahmefällen separat zu behandeln.

  

Gibt es eine Möglichkeit alle geschaffen subprocess, um sicherzustellen, sind tot an der Ausfahrt Zeit eines Programms Python? Durch subprocess meine ich diejenigen mit subprocess.Popen () erstellt wurde.

Sie könnten Verkapselung verletzen und Test , dass alle Popen Prozesse beendet haben, indem Sie

subprocess._cleanup()
print subprocess._active == []
  

Wenn nicht, sollte ich iterieren alle die Ausgabe kills über und dann tötet -9? etwas sauberer?

Sie können nicht gewährleisten, dass alle Teilprozesse tot sind ohne jeden Überlebenden zu gehen und zu töten. Aber wenn Sie dieses Problem haben, ist es wahrscheinlich, weil Sie ein tieferes Design-Problem haben.

Eine Lösung für Fenster sein, um den win32 Job api zum Beispiel zu verwenden Wie zerstöre ich automatisch untergeordnete Prozesse in Windows?

Hier ist eine bestehende Python-Implementierung

https://gist.github.com/ubershmekel/119697afba2eaecc6330

Ich brauchte eigentlich, dies zu tun, aber es beteiligt Remote-Befehle ausgeführt werden. Wir wollten die Prozesse in der Lage sein zu stoppen, indem die Verbindung zum Server zu schließen. Auch wenn zum Beispiel Sie in der Python-repl ausführen, können Sie wählen, als Vordergrund laufen, wenn Sie in der Lage sein wollen, Ctrl-C zu verwenden, um zu beenden.

import os, signal, time

class CleanChildProcesses:
    """
    with CleanChildProcesses():
        Do work here
    """
    def __init__(self, time_to_die=5, foreground=False):
        self.time_to_die = time_to_die  # how long to give children to die before SIGKILL
        self.foreground = foreground  # If user wants to receive Ctrl-C
        self.is_foreground = False
        self.SIGNALS = (signal.SIGHUP, signal.SIGTERM, signal.SIGABRT, signal.SIGALRM, signal.SIGPIPE)
        self.is_stopped = True  # only call stop once (catch signal xor exiting 'with')

    def _run_as_foreground(self):
        if not self.foreground:
            return False
        try:
            fd = os.open(os.ctermid(), os.O_RDWR)
        except OSError:
            # Happens if process not run from terminal (tty, pty)
            return False

        os.close(fd)
        return True

    def _signal_hdlr(self, sig, framte):
        self.__exit__(None, None, None)

    def start(self):
        self.is_stopped = False
        """
        When running out of remote shell, SIGHUP is only sent to the session
        leader normally, the remote shell, so we need to make sure we are sent 
        SIGHUP. This also allows us not to kill ourselves with SIGKILL.
        - A process group is called orphaned when the parent of every member is 
            either in the process group or outside the session. In particular, 
            the process group of the session leader is always orphaned.
        - If termination of a process causes a process group to become orphaned, 
            and some member is stopped, then all are sent first SIGHUP and then 
            SIGCONT.
        consider: prctl.set_pdeathsig(signal.SIGTERM)
        """
        self.childpid = os.fork()  # return 0 in the child branch, and the childpid in the parent branch
        if self.childpid == 0:
            try:
                os.setpgrp()  # create new process group, become its leader
                os.kill(os.getpid(), signal.SIGSTOP)  # child fork stops itself
            finally:
                os._exit(0)  # shut down without going to __exit__

        os.waitpid(self.childpid, os.WUNTRACED)  # wait until child stopped after it created the process group
        os.setpgid(0, self.childpid)  # join child's group

        if self._run_as_foreground():
            hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN)  # ignore since would cause this process to stop
            self.controlling_terminal = os.open(os.ctermid(), os.O_RDWR)
            self.orig_fore_pg = os.tcgetpgrp(self.controlling_terminal)  # sends SIGTTOU to this process
            os.tcsetpgrp(self.controlling_terminal, self.childpid)
            signal.signal(signal.SIGTTOU, hdlr)
            self.is_foreground = True

        self.exit_signals = dict((s, signal.signal(s, self._signal_hdlr))
                                 for s in self.SIGNALS)                                     

    def stop(self):
        try:
            for s in self.SIGNALS:
                #don't get interrupted while cleaning everything up
                signal.signal(s, signal.SIG_IGN)

            self.is_stopped = True

            if self.is_foreground:
                os.tcsetpgrp(self.controlling_terminal, self.orig_fore_pg)
                os.close(self.controlling_terminal)
                self.is_foreground = False

            try:
                os.kill(self.childpid, signal.SIGCONT)
            except OSError:
                """
                can occur if process finished and one of:
                - was reaped by another process
                - if parent explicitly ignored SIGCHLD
                    signal.signal(signal.SIGCHLD, signal.SIG_IGN)
                - parent has the SA_NOCLDWAIT flag set 
                """
                pass

            os.setpgrp()  # leave the child's process group so I won't get signals
            try:
                os.killpg(self.childpid, signal.SIGINT)
                time.sleep(self.time_to_die)  # let processes end gracefully
                os.killpg(self.childpid, signal.SIGKILL)  # In case process gets stuck while dying
                os.waitpid(self.childpid, 0)  # reap Zombie child process
            except OSError as e:
                pass
        finally:
            for s, hdlr in self.exit_signals.iteritems():
                signal.signal(s, hdlr)  # reset default handlers

    def __enter__(self):
        if self.is_stopped:
            self.start()

    def __exit__(self, exit_type, value, traceback):
        if not self.is_stopped:
            self.stop()

Dank Malcolm Handley für den ersten Entwurf. Fertig mit python2.7 auf Linux.

eine Lösung für Linux finden Sie (ohne die Installation prctl):

def _set_pdeathsig(sig=signal.SIGTERM):
    """help function to ensure once parent process exits, its childrent processes will automatically die
    """
    def callable():
        libc = ctypes.CDLL("libc.so.6")
        return libc.prctl(1, sig)
    return callable


subprocess.Popen(your_command, preexec_fn=_set_pdeathsig(signal.SIGTERM)) 

Das ist das, was ich für meinen Posix-App tat:

Wenn Ihre App existiert die kill () -Methode dieser Klasse aufrufen: http://www.pixelbeat.org/libs/subProcess.py

Beispiel hier verwenden: http://code.google.com/p/ fslint / source / browse / trunk / fslint-gui # 608

Sie können versuchen, subalive, ein Paket, das ich für ähnliches Problem geschrieben haben. Es nutzt Routine- Ping über RPC und der Slave-Prozess endet automatisch, wenn der Meister am Leben Pings aus irgendeinem Grund stehen bleibt.

https://github.com/waszil/subalive

Beispiel für Master:

from subalive import SubAliveMaster

# start subprocess with alive keeping
SubAliveMaster(<path to your slave script>)

# do your stuff
# ...

Beispiel für Slave subprocess:

from subalive import SubAliveSlave

# start alive checking
SubAliveSlave()

# do your stuff
# ...
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top