如何在使用subprocess.Popen后进行清理?

15

我有一个长时间运行的Python脚本,其中包含一个Perl工作子进程。数据通过其标准输入和输出发送到子进程中并返回。定期地,需要重新启动子进程。

不幸的是,运行一段时间后,它会耗尽文件('too many open files')。lsof显示许多剩余的打开管道。

清理Popen'd进程的正确方法是什么?这是我现在正在做的:

def start_helper(self):
    # spawn perl helper
    cwd = os.path.dirname(__file__)
    if not cwd:
        cwd = '.'

    self.subp = subprocess.Popen(['perl', 'theperlthing.pl'], shell=False, cwd=cwd,
                                 stdin=subprocess.PIPE, stdout=subprocess.PIPE,
                                 bufsize=1, env=perl_env)

def restart_helper(self):
    # clean up
    if self.subp.stdin:
        self.subp.stdin.close()
    if self.subp.stdout:
        self.subp.stdout.close()
    if self.subp.stderr:
        self.subp.stderr.close()

    # kill
    try:
        self.subp.kill()
    except OSError:
        # can't kill a dead proc
        pass
    self.subp.wait() # ?

    self.start_helper()

1
Popen.kill(或 Popen.terminate)是您最好的选择。 - Santa
1
这里有一个与subprocess无关的错误,但它可能会对_cleanup()函数有所启示。http://bugs.python.org/issue1731717 - jfs
6
如果您不在Windows上,请使用close_fds=True(py3k默认) - jfs
2
顺便提一下,在某些系统上,打开文件的数量限制非常小。 - jfs
我不想说,但我真的想知道为什么perl脚本首先必须定期被杀死和重新启动! - Michael Scott Shappe
显示剩余6条评论
2个回答

7
我认为这就是你需要的全部内容:
def restart_helper(self):
    # kill the process if open
    try:
        self.subp.kill()
    except OSError:
        # can't kill a dead proc
        pass

    self.start_helper()
    # the wait comes after you opened the process
    # if you want to know how the process ended you can add
    # > if self.subp.wait() != 0:
    # usually a process that exits with 0 had no errors
    self.subp.wait()

据我所知,在popen进程被终止之前,所有文件对象都将被关闭。

wait() 是确保不会留下子进程和未关闭管道的关键。 - dkagedal
我认为这最终成为了事实。 - dkuebric

1
一个快速的实验表明,x = open("/etc/motd"); x = 1 可以在结束时自动清理并不留下打开的文件描述符。如果你放弃对 subprocess.Popen 的最后一个引用,管道似乎会一直保留。你是否有可能重新调用了 start_helper()(甚至其他的 Popen),而没有显式地关闭和停止旧的进程?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接