【问题标题】: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。

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

【问题讨论】:

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

标签: python subprocess


【解决方案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 值出现的一个有趣的地方是在为waitcommunicate 使用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 属性是 initializedNone 并且只会在少数地方发生变化,主要是调用 _handle_exitstatus 以传递实际的返回码。

    【讨论】:

      【解决方案4】:

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

      试试这个代码:

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

      希望这有帮助!

      【讨论】:

      • 对不起,这没有帮助。它只是造成缓冲区溢出
      猜你喜欢
      • 2022-06-15
      • 2011-03-07
      • 1970-01-01
      • 1970-01-01
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 2012-10-23
      相关资源
      最近更新 更多