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

发布于 2024-11-08 21:42:23 字数 1235 浏览 0 评论 0原文

我试图检测安装程序何时从 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子进程模块->须藤 ->运行安装程序-> java-> (未知)

I am trying to detect when an installation program finishes executing from within a Python script. Specifically, the application is the Oracle 10gR2 Database. Currently I am using the subprocess module with Popen. Ideally, I would simply use the wait() method to wait for the installation to finish executing, however, the documented command actually spawns child processes to handle the actual installation. Here is some sample code of the failing code:

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()

There is a similar question here: Killing a subprocess including its children from python, but the selected answer does not address the children issue, instead it instructs the user to call directly the application to wait for. I am looking for a specific solution that will wait for all children of the subprocess. What if there are an unknown number of subprocesses? I will select the answer that addresses the issue of waiting for all children subprocesses to finish.

More clarity on failure: The child processes continue executing after the wait() command since that command only waits for the top level process (in this case it is 'sudo'). Here is a simple diagram of the known child processes in this problem:
Python subprocess module -> Sudo -> runInstaller -> java -> (unknown)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

似最初 2024-11-15 21:42:23

好的,这是一个仅在 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-创建守护进程-python-way/

Ok, here is a trick that will work only under Unix. It is similar to one of the answers to this question: Ensuring subprocesses are dead on exiting Python program. The idea is to create a new process group. You can then wait for all processes in the group to terminate.

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)

I have not tested this. It creates an extra subprocess to be the leader of the process group, but avoiding that is (I think) quite a bit more complicated.

I found this web page to be helpful as well. http://code.activestate.com/recipes/278731-creating-a-daemon-the-python-way/

岁月如刀 2024-11-15 21:42:23

您可以使用 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 的结果:

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

希望这可以有所帮助:)

You can just use os.waitpid with the the pid set to -1, this will wait for all the subprocess of the current process until they finish:

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

This is the result of pstree <pid> of different subprocess forked:

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

Hope this can help :)

巷子口的你 2024-11-15 21:42:23

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

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

问候

Check out the following link http://www.oracle-wiki.net/startdocsruninstaller which details a flag you can use for the runInstaller command.

This flag is definitely available for 11gR2, but I have not got a 10g database to try out this flag for the runInstaller packaged with that version.

Regards

感情洁癖 2024-11-15 21:42:23

我到处看看似乎都说在一般情况下不可能解决这个问题。我创建了一个名为“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 上,很容易 叉?)。这至少应该让您开始,如果它对您有用,我有很多关于如何优化它的想法。

Everywhere I look seems to say it's not possible to solve this in the general case. I've whipped up a library called 'pidmon' that combines some answers for Windows and Linux and might do what you need.

I'm planning to clean this up and put it on github, possibly called 'pidmon' or something like that. I'll post a link if/when I get it up.

EDIT: It's available at http://github.com/dbarnett/python-pidmon.

I made a special waitpid function that accepts a graft_func argument so that you can loosely define what sort of processes you want to wait for when they're not direct children:

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

or, as a shotgun approach, to just wait for any processes started since the call to waitpid to stop again, do:

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

Note that this is still barely tested on Windows and seems very slow on Windows (but did I mention it's on github where it's easy to fork?). This should at least get you started, and if it works at all for you, I have plenty of ideas on how to optimize it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文