5

我试图检测安装程序何时从 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 subprocess module -> Sudo -> runInstaller -> java -> (unknown)

4

4 回答 4

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/

于 2011-05-23T20:58:17.523 回答
2

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

该标志绝对适用于 11gR2,但我没有 10g 数据库来为与该版本打包的 runInstaller 试用此标志。

问候

于 2011-07-12T14:30:32.107 回答
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

希望这可以帮助:)

于 2011-05-23T22:37:16.850 回答
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 上很容易分叉?)。这至少应该让你开始,如果它对你有用,我有很多关于如何优化它的想法。

于 2011-05-27T15:35:47.003 回答