75

Python プログラムの終了時に、作成されたすべてのサブプロセスが停止していることを確認する方法はありますか? サブプロセスとは、subprocess.Popen() で作成されたものを意味します。

そうでない場合、発行しているすべてのキルを繰り返してから、-9 をキルする必要がありますか? 何かきれい?

4

14 に答える 14

57

これには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!

-このプロセス(親プロセス)が強制終了された場合、登録された関数は実行されません。

次のWindowsメソッドは、Python>=2.6では不要になりました

Windowsでプロセスを強制終了する方法は次のとおりです。Popenオブジェクトにはpid属性があるため、success = 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
于 2008-11-26T13:36:39.857 に答える
50

*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 (別名kill -9) へ。シグナルの合間に少し待って、プロセスが正常に終了する前にプロセスを終了さkill -9せます。

于 2008-11-26T22:02:49.697 に答える
16

subprocess.Popen.wait()彼らが死んでいることを確認する唯一の方法です。実際、POSIX OS では、子供を待つ必要があります。多くの *nix は「ゾンビ」プロセスを作成します: 親が待たなかった死んだ子です。

子が適度によく書かれている場合、それは終了します。多くの場合、子供たちは PIPE から読みます。入力を閉じることは、店を閉じて終了する必要があるという子供への大きなヒントです。

子にバグがあり、終了しない場合は、それを強制終了する必要がある場合があります。このバグを修正する必要があります。

子が「永久に提供する」ループであり、終了するように設計されていない場合は、それを強制終了するか、強制的に終了させる入力またはメッセージを提供する必要があります。


編集。

標準の OS では、os.kill( PID, 9 ). Kill -9 は過酷です。SIGABRT (6?) または SIGTERM (15) でそれらを強制終了できる場合は、より丁寧です。

Windows OS では、機能する がありませんos.kill。Windows でプロセスを終了するには、このActiveState レシピを参照してください。

WSGI サーバーである子プロセスがあります。それらを終了するには、特別な URL で GET を実行します。これにより、子はクリーンアップして終了します。

于 2008-11-26T10:56:21.287 に答える
3

投票( )

子プロセスが終了したかどうかを確認します。returncode 属性を返します。

于 2008-11-26T10:32:24.970 に答える
3

Windows の解決策は、win32 ジョブ API を使用することです。たとえば、Windows で子プロセスを自動的に破棄するにはどうすればよいですか?

ここに既存のpython実装があります

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

于 2016-02-22T22:17:02.460 に答える
2

実際にこれを行う必要がありましたが、リモート コマンドの実行が必要でした。サーバーへの接続を閉じることでプロセスを停止できるようにしたかったのです。また、たとえば、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 で完了。

于 2016-12-29T14:39:15.580 に答える
2

Python プログラムの終了時に、作成されたすべてのサブプロセスが停止していることを確認する方法はありますか? サブプロセスとは、subprocess.Popen() で作成されたものを意味します。

カプセル化に違反し、すべての Popen プロセスが終了したことをテストできます。

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

そうでない場合、発行しているすべてのキルを繰り返してから、-9 をキルする必要がありますか? 何かきれい?

外に出てすべての生存者を殺さずに、すべてのサブプロセスが死んでいることを保証することはできません。しかし、この問題がある場合、それはおそらく、より深い設計上の問題があるためです。

于 2008-11-26T10:54:03.553 に答える
-1

これは私がposixアプリに対して行ったことです:

アプリが存在する場合、このクラスの kill() メソッドを呼び出します: http://www.pixelbeat.org/libs/subProcess.py

ここでの使用例: http://code.google.com/p/fslint/source/browse/trunk/fslint-gui#608

于 2008-11-26T11:39:11.123 に答える
-1

Python コードのヘルプ: http://docs.python.org/dev/library/subprocess.html#subprocess.Popen.wait

于 2012-03-06T05:48:02.733 に答える