有没有办法检查子进程是不是仍在运行?
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()
?
@asongtoruin 打印无,即使过程完成。
进程完成后应该停止打印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)
希望这有帮助!
【讨论】:
对不起,这没有帮助。它只是造成缓冲区溢出以上是关于有没有办法检查子进程是不是仍在运行?的主要内容,如果未能解决你的问题,请参考以下文章