有没有一种方法,以确保所有创造的子流程是死在退出时间的蟒蛇的程序?通过子流程我的意思是那些有子流程.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

下面是一种方法来杀死在窗口的处理。您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的,也许使用进程组可以帮你 - 你能赶上你的子进程催生和子流程

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

的另一个考虑是将信号升级:从SIGTERM(对于kill缺省信号)SIGKILL(a.k.a kill -9)。等待的信号之间的短而得到的处理的机会,你kill -9之前完全退出。

subprocess.Popen.wait()是确保他们死的唯一途径。事实上,POSIX操作系统的要求,你就等着你的儿女。许多* nix中的将创建一个“僵尸”的过程:一个死孩子的母没有等到

如果孩子是相当好写入时,它终止。通常情况下,儿童从管道的读取。关闭输入是一个很大的提示,它应该关店退出的孩子。

如果孩子有错误,并不会终止,则可能必须杀死它。您应该修复这个bug。

如果孩子是“服务 - 永远”的循环,而不是旨在终止,您应该杀了它,或者提供一些输入或消息,这将迫使它终止。


编辑。

在标准的操作系统的,你有os.kill( PID, 9 )。杀-9恶劣,BTW。如果你可以用SIGABRT(6?)或SIGTERM(15)杀死他们,是比较客气的。

在Windows操作系统,你没有那个工作的os.kill。看这个 ActiveState的配方在Windows终止进程。

我们有一个是WSGI服务器的子进程。要终止他们,我们做一个特殊的URL一个GET;这导致子清理并退出。

警告:Linux only!你可以让你的孩子接收信号的时其父母死亡。

首先安装python prctl==升级到1.5.0然后改变你的父母代码发动你的孩子流程如下

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

什么这个说的是:

  • 发射子流程:睡眠100
  • 后forking和前exec的子流程,儿童的登记册"送我一个SIGKILL 当我父终止".
  

轮询()

     

检查子进程终止。   返回RETURNCODE属性。

我需要这个问题的一个小的变化(清理子流程,但不退出Python程序本身),并且由于它不是这里提到的其它的答案中:

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

setsid将在一个新的会话中运行该程序,从而分配新进程组它和它的孩子。呼吁它os.killpg因而不会打倒自己的Python进程也。

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

当然,你可以使用try /做到这一点,除了/最后,但你必须单独处理的特殊和非特殊情况下。

  

有没有一种方法,以确保所有已创建子进程正处在一个Python程序的退出时间死了吗?由子我的意思是那些具有subprocess.Popen()创建。

您可能违反封装的测试的所有POPEN进程已经做终止

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

如果不是,我应该遍历所有发行杀死,然后杀死-9?任何清洁器?

您不能确保所有的子进程都没有走出去,杀死每一位幸存者,死了。但是,如果你有这样的问题,很可能是因为你有一个更深层次的设计问题。

一个用于窗口解决方案可以是使用Win32 API作业例如如何自动销毁子进程在Windows?

下面是一个现有Python实现

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

我确实需要做到这一点,但它涉及到运行远程命令。我们希望能够通过关闭与服务器的连接,以停止进程。另外,如果,例如,你在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()

由于马尔科姆汉德利用于初始设计。完成在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的应用程序:

当你的应用存在调用这个类的杀()方法: http://www.pixelbeat.org/libs/subProcess.py

实施例使用这里: http://code.google.com/p/ fslint /源/浏览/中继/ fslint桂#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