문제

Python 프로그램의 출구 시간에 생성 된 모든 하위 프로세스가 죽을 수있는 방법이 있습니까? 하위 프로세스로는 하위 프로세스로 생성 된 것을 의미합니다 .popen ().

그렇지 않다면 발행 된 모든 살인을 반복 한 다음 -9를 죽여야합니까? 더 깨끗한 것이 있습니까?

도움이 되었습니까?

해결책

당신이 사용할 수있는 atexit 이를 위해 프로그램이 종료 될 때 실행할 정리 작업을 등록하십시오.

atexit.register (func [, *args [, ** kargs]])))

정리 과정에서는 대기를 구현하고 원하는 시간 초과가 발생할 때 죽일 수도 있습니다.

>>> 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!

메모 -이 프로세스 (부모 프로세스)가 사망 한 경우 등록 기능이 실행되지 않습니다.

Python> = 2.6에는 다음 Windows 방법이 더 이상 필요하지 않습니다.

Windows에서 프로세스를 죽이는 방법은 다음과 같습니다. Popen 객체에는 PID 속성이 있으므로 전화 할 수 있습니다. 성공 = win_kill (p.pid) (필요합니다 pywin32 설치) :

    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

다른 팁

*Nix 's에서 프로세스 그룹을 사용하면 도움이 될 수 있습니다. 하위 프로세스에서도 산란 한 하위 프로세스를 잡을 수 있습니다.

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

또 다른 고려 사항은 신호를 에스컬레이션하는 것입니다. kill) Sigkill에 (일명 kill -9). 신호 사이에 짧은 시간을 기다리려면 프로세스가 당신 앞에 깨끗하게 빠져 나갈 수있는 기회를 제공합니다. kill -9 그것.

그만큼 subprocess.Popen.wait() 그들이 죽었는지 확인하는 유일한 방법입니다. 실제로 Posix OS는 자녀를 기다릴 것을 요구합니다. 많은 *닉스는 부모가 기다리지 않은 죽은 아이 인 "좀비"과정을 만들 것입니다.

아이가 합리적으로 잘 작성된 경우 종료됩니다. 종종 아이들은 파이프를 읽습니다. 입력을 닫는 것은 어린이가 상점을 닫고 나가야한다는 큰 힌트입니다.

아이가 벌레가 있고 종료되지 않으면 죽여야 할 수도 있습니다. 이 버그를 수정해야합니다.

아이가 "서브 프레버"루프이고 종료되도록 설계되지 않은 경우, 그것을 죽이거나 입력을 강요 할 수있는 입력이나 메시지를 제공해야합니다.


편집하다.

표준 OS에서는 있습니다 os.kill( PID, 9 ). 살인 -9는 거칠다, btw. Sigabrt (6?) 또는 Sigterm (15)으로 그들을 죽일 수 있다면 더 정중합니다.

Windows OS에는 없습니다 os.kill 작동합니다. 이거 봐요 레시피를 활성화하십시오 Windows에서 프로세스를 종료합니다.

WSGI 서버 인 아동 프로세스가 있습니다. 그들을 종료하기 위해 우리는 특별한 URL을 얻습니다. 이로 인해 아이가 청소하고 나가게됩니다.

경고 : Linux 전용! 부모가 죽을 때 자녀가 신호를받을 수 있습니다.

먼저 Python-PRCTL == 1.5.0을 설치 한 다음 부모 코드를 변경하여 다음과 같이 자녀 프로세스를 시작하십시오.

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

이것이 말하는 것은 다음과 같습니다.

  • Subprocess 발사 : Sleep 100
  • 포킹 후 및 하위 프로세스의 실행 전에, 아동은 "부모가 종료 될 때 Sigkill을 보내주십시오"를 등록합니다.

설문 조사 ()

아동 프로세스가 종료되었는지 확인하십시오. returncode 속성을 반환합니다.

이 문제의 작은 변형이 필요했지만 (하위 프로세서를 청소하지만 Python 프로그램 자체를 종료하지는 않음) 다른 답변 중에서 언급되지 않았기 때문입니다.

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

setsid 새로운 세션에서 프로그램을 실행하여 새로운 프로세스 그룹을 IT와 어린이에게 할당합니다. 부름 os.killpg 따라서 그것은 당신의 자신의 파이썬 프로세스도 무너 뜨리지 않을 것입니다.

ORIP의 답변은 도움이되지만 프로세스를 죽이고 오류 코드를 반환한다는 단점이 있습니다. 나는 다음과 같은 것을 피했다 :

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

그리고:

  with CleanChildProcesses():
    # Do your work here

물론 시도/제외/최종적 으로이 작업을 수행 할 수 있지만 예외적이고 비 예외적인 사례를 별도로 처리해야합니다.

Python 프로그램의 출구 시간에 생성 된 모든 하위 프로세스가 죽을 수있는 방법이 있습니까? 하위 프로세스로는 하위 프로세스로 생성 된 것을 의미합니다 .popen ().

캡슐화를 위반할 수 있습니다 테스트 모든 Popen 프로세스는 수행하여 종료되었습니다

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

그렇지 않다면 발행 된 모든 살인을 반복 한 다음 -9를 죽여야합니까? 더 깨끗한 것이 있습니까?

모든 서브 프로세스가 외출하거나 모든 생존자를 죽이지 않고 죽었는지 확인할 수는 없습니다. 그러나이 문제가 있다면 디자인 문제가 더 심해서 아마도 일 것입니다.

Windows 용 솔루션은 Win32 작업 API를 사용하는 것입니다. Windows에서 자식 프로세스를 자동으로 파괴하려면 어떻게해야합니까?

기존 Python 구현은 다음과 같습니다

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

실제로이 작업을 수행해야했지만 원격 명령을 실행하는 것이 포함되었습니다. 서버 연결을 닫아 프로세스를 중지하고 싶었습니다. 또한, 예를 들어, Python Repl에서 실행중인 경우 CTRL-C를 사용하여 종료 할 수 있으려면 전경으로 실행하도록 선택할 수 있습니다.

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

초기 디자인에 대한 Malcolm Handley에게 감사드립니다. Linux에서 Python2.7로 완료되었습니다.

Linux 용 솔루션을 찾으십시오 (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)) 

이것이 제가 POSIX 앱에서 한 일입니다.

앱이 존재하면이 클래스의 kill () 메소드를 호출합니다.http://www.pixelbeat.org/libs/subprocess.py

예제 여기서 사용 :http://code.google.com/p/fslint/source/browse/trunk/fslint-gui#608

당신은 시도 할 수 있습니다 subalive, 내가 비슷한 문제에 대해 쓴 패키지. RPC를 통해 주기적으로 살아있는 핑을 사용하며, 노예 프로세스는 마스터가 어떤 이유로 살아있는 핑을 멈출 때 자동으로 종료됩니다.

https://github.com/waszil/subalive

마스터의 예 :

from subalive import SubAliveMaster

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

# do your stuff
# ...

슬레이브 하위 프로세스의 예 :

from subalive import SubAliveSlave

# start alive checking
SubAliveSlave()

# do your stuff
# ...
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top