有没有办法检查子进程是不是仍在运行?

Posted

技术标签:

【中文标题】有没有办法检查子进程是不是仍在运行?【英文标题】:Is there a way to check if a subprocess is still running?有没有办法检查子进程是否仍在运行? 【发布时间】:2017-09-02 14:57:15 【问题描述】:

我正在用 Python 中的 subprocess.Popen 启动许多子进程。 我想检查一个这样的过程是否已经完成。我找到了两种检查子进程状态的方法,但似乎都强制该进程完成。 一种是使用 process.communicate() 并打印返回码,如here 所述。 另一个是简单地调用 process.wait() 并检查它是否返回 0。

有没有办法检查一个进程是否仍在运行,而无需等待它完成?

【问题讨论】:

Popen.poll()? @ason​​gtoruin 打印无,即使过程完成。 进程完成后应该停止打印None。你如何调用你的子进程? subprocess.Popen(["python", scriptname], stdout = open(os.devnull, 'w')) 【参考方案1】:

Ouestion:...一种检查进程是否仍在运行的方法...

例如,您可以这样做:

p = subprocess.Popen(...
"""
A None value indicates that the process hasn't terminated yet.
"""
poll = p.poll()
if poll is None:
  # p.subprocess is alive

Python » 3.6.1 Documentation popen-objects

用 Python:3.4.2 测试

【讨论】:

我可以做 p.poll()。即使在该过程完成后,这也会返回 None 。我知道这一点是因为我调用的脚本会生成一个出现的输出文件,但它仍然返回 None。另外,我可以打印 p.wait() 给出 0,但之后打印 p.poll() 仍然给出 None。 语义,但我相信if poll is None是首选的写法。 Argh,对不起,我犯了一个错误,在创建新进程后使用 poll,而不是旧进程。 p.poll() 确实是这样做的方法(运行时为None,成功完成时为0)。 它也适用于 Python 2.7.10 我起初对这个解决方案有疑问,因为我在 p.terminate 之后立即使用 p.poll 并且仍然没有。在两者之间添加一个小延迟解决了这个问题。如果其他人遇到此问题,希望这会有所帮助。【参考方案2】:

做事

myProcessIsRunning = poll() is None 

正如主要答案所建议的那样,这是检查进程是否正在运行的推荐方法和最简单的方法。 (它也适用于 jython)

如果您手头没有流程实例来检查它。 然后使用操作系统的TaskList/Ps进程。

在 Windows 上,我的命令如下所示:

filterByPid = "PID eq %s" % pid
        pidStr = str(pid)
        commandArguments = ['cmd', '/c', "tasklist", "/FI", filterByPid, "|", "findstr",  pidStr ]

这本质上与下面的命令行做同样的事情:

cmd /c "tasklist /FI "PID eq 55588" | findstr 55588"

在 linux 上,我使用以下代码执行完全相同的操作:

pidStr = str(pid)
commandArguments = ['ps', '-p', pidStr ]

根据是否找到进程,ps 命令已经返回错误代码 0 / 1。在 Windows 上,您需要 find string 命令。

这与以下堆栈溢出线程中讨论的方法相同:

Verify if a process is running using its PID in JAVA

注意: 如果您使用这种方法,请记住将您的命令调用包装在 try/except 中:

try:
    foundRunningProcess = subprocess.check_output(argumentsArray, **kwargs)
    return True
except Exception as err:
    return False

注意,如果您使用 VS Code 并使用纯 Python 和 Jython 进行开发,请小心。 在我的环境中,我错觉 poll() 方法不起作用,因为我怀疑必须结束的进程确实正在运行。 这个过程启动了 Wildfly。在我要求停止 wildfly 后,shell 仍在等待用户“按任意键继续......”。

为了完成这个过程,在纯 python 中,以下代码正在运行:

process.stdin.write(os.linesep)

在 jython 上,我必须将这段代码修复为如下所示:

print >>process.stdin, os.linesep

有了这个不同,这个过程确实完成了。 jython.poll() 开始告诉我该过程确实完成了。

【讨论】:

【参考方案3】:

正如其他答案所建议的那样,None 是当子流程尚未返回任何代码时“返回代码”的设计占位符。

returncode 属性的文档支持这一点(强调我的):

子返回码,由poll()wait() 设置(间接由communicate() 设置)。 None 值表示进程尚未终止

负值 -N 表示子进程被信号 N 终止(仅限 POSIX)。

这个None 值出现的一个有趣的地方是在为wait 或communicate 使用timeout 参数时。

如果进程在 timeout 秒后没有终止,则会引发 TimeoutExpired 异常。

如果您捕获该异常并检查 returncode 属性,它确实是 None

import subprocess
with subprocess.Popen(['ping','127.0.0.1']) as p:
    try:
        p.wait(timeout=3)
    except subprocess.TimeoutExpired:
        assert p.returncode is None

如果您查看 subprocess 的源代码,您会看到引发的异常。 https://github.com/python/cpython/blob/47be7d0108b4021ede111dbd15a095c725be46b7/Lib/subprocess.py#L1930-L1931

如果您在该源中搜索self.returncode is,您会发现库作者依靠None 返回代码设计来推断应用程序是否正在运行的许多用途。 returncode 属性是 initialized 到 None 并且只会在少数地方发生变化,主要是调用 _handle_exitstatus 以传递实际的返回码。

【讨论】:

【参考方案4】:

您可以使用 subprocess.check_output 查看您的输出。

试试这个代码:

import subprocess
subprocess.check_output(['your command here'], shell=True, stderr=subprocess.STDOUT)

希望这有帮助!

【讨论】:

对不起,这没有帮助。它只是造成缓冲区溢出

以上是关于有没有办法检查子进程是不是仍在运行?的主要内容,如果未能解决你的问题,请参考以下文章

C++ fork 进程但不是子进程

节点或shell脚本中有没有办法知道子进程是不是启动了自己的子进程?

阻止写入标准输出

如何检查子进程是不是正确终止? [复制]

NodeJs - 检查子进程是不是成功启动

进程管理