Python:如何判断子进程的所有子进程已完成运行

5 投票
4 回答
4577 浏览
提问于 2025-04-16 18:12

我正在尝试在一个Python脚本中检测安装程序何时执行完毕。具体来说,我要处理的是Oracle 10gR2数据库。目前,我使用的是subprocess模块中的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()

这里有一个类似的问题:从Python中终止一个子进程及其子进程,但选中的答案并没有解决子进程的问题,而是建议用户直接调用应用程序来等待。我在寻找一个具体的解决方案,能够等待所有子进程完成。如果有不确定数量的子进程该怎么办呢?我会选择那个能解决等待所有子进程完成问题的答案。

关于失败的更多说明:wait()命令执行后,子进程仍然在继续运行,因为这个命令只会等待顶层进程(在这个例子中是'sudo')。以下是这个问题中已知子进程的简单示意图: Python subprocess模块 -> Sudo -> runInstaller -> java -> (未知)

4 个回答

2

请查看以下链接 http://www.oracle-wiki.net/startdocsruninstaller,里面详细介绍了一个可以用于runInstaller命令的标志。

这个标志在11gR2版本中肯定是可以用的,但我没有10g版本的数据库来测试这个标志在那个版本的runInstaller中的效果。

祝好

2

你可以直接使用 os.waitpid,把进程ID(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

希望这能帮到你 :)

3

好的,这里有一个技巧,只在Unix系统下有效。这个方法和这个问题的某个答案有点相似:确保在退出Python程序时子进程已经结束。这个想法是创建一个新的进程组。然后你可以等待这个组里的所有进程都结束。

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/

撰写回答