Python:如何确定子进程子进程已全部运行完毕

时间:2011-05-23 20:18:09

标签: python oracle10g subprocess child-process spawning

我正在尝试检测安装程序何时从Python脚本中执行。具体来说,该应用程序是Oracle 10gR2数据库。目前我正在使用Popen的子进程模块。理想情况下,我只是使用wait()方法等待安装完成执行,但是,记录的命令实际上生成子进程来处理实际安装。以下是失败代码的示例代码:

import subprocess
OUI_DATABASE_10GR2_SUBPROCESS = ['sudo',
                                 '-u',
                                 'oracle',
                                 os.path.join(DATABASE_10GR2_TMP_PATH,
                                              'database',
                                              'runInstaller'),
                                 '-ignoreSysPrereqs',
                                 '-silent',
                                 '-noconfig',
                                 '-responseFile '+ORACLE_DATABASE_10GR2_SILENT_RESPONSE]
oracle_subprocess = subprocess.Popen(OUI_DATABASE_10GR2_SUBPROCESS)
oracle_subprocess.wait()

此处有一个类似的问题:Killing a subprocess including its children from python,但所选答案并未解决子问题,而是指示用户直接调用应用程序等待。我正在寻找一个等待子进程的所有子进程的特定解决方案。如果有不确定数量的子流程怎么办?我将选择解决等待所有子进程完成的问题的答案。

故障更清晰:子进程在wait()命令之后继续执行,因为该命令只等待顶级进程(在这种情况下它是'sudo')。以下是此问题中已知子进程的简单图表: Python子进程模块 - > Sudo - > runInstaller - > java - > (未知)

4 个答案:

答案 0 :(得分:3)

好的,这是一个仅适用于Unix的技巧。它类似于这个问题的答案之一:Ensuring subprocesses are dead on exiting Python program。我们的想法是创建一个新的流程组。然后,您可以等待组中的所有进程终止。

pid = os.fork()
if pid == 0:
    os.setpgrp()
    oracle_subprocess = subprocess.Popen(OUI_DATABASE_10GR2_SUBPROCESS)
    oracle_subprocess.wait()
    os._exit(0)
else:
    os.waitpid(-pid)

我没有测试过这个。它创建了一个额外的子流程作为流程组的领导者,但避免这种情况(我认为)相当复杂。

我发现这个网页也很有帮助。 http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/

答案 1 :(得分:2)

你可以使用os.waitpid并将pid设置为-1,这将等待当前进程的所有子进程,直到它们完成:

import os
import sys
import subprocess


proc = subprocess.Popen([sys.executable,
                         '-c',
                         'import subprocess;'
                         'subprocess.Popen("sleep 5", shell=True).wait()'])

pid, status = os.waitpid(-1, 0)

print pid, status

这是分叉的不同子流程pstree <pid>的结果:

python───python───sh───sleep

希望这有助于:)

答案 2 :(得分:2)

查看以下链接http://www.oracle-wiki.net/startdocsruninstaller,其中详细说明了可用于runInstaller命令的标志。

这个标志肯定适用于11gR2,但是我没有10g数据库为这个版本打包的runInstaller试用这个标志。

此致

答案 3 :(得分:1)

我看的每个地方似乎都说在一般情况下不可能解决这个问题。我创建了一个名为“pidmon”的库,它结合了Windows和Linux的一些答案,可能会做你需要的。

我打算把它清理干净并把它放在github上,可能叫做'pidmon'或类似的东西。如果/我什么时候发布,我会发布一个链接。

编辑:可在http://github.com/dbarnett/python-pidmon处找到。

我创建了一个特殊的waitpid函数,它接受一个graft_func参数,这样你就可以松散地定义当你不是直接孩子时想要等待的进程:

import pidmon
pidmon.waitpid(oracle_subprocess.pid, recursive=True,
        graft_func=(lambda p: p.name == '???' and p.parent.pid == ???))

或者,作为一个猎枪方法,只要等待自waitpid调用再次停止以来开始的任何进程,请执行:

import pidmon
pidmon.waitpid(oracle_subprocess.pid, graft_func=(lambda p: True))

请注意,这仍然在Windows上几乎没有经过测试,在Windows上看起来很慢(但是我在github上提到它很容易分叉吗?)。这至少应该让你开始,如果它对你有用,我对如何优化它有很多想法。