Python:在后台进程上使用popen poll

23

我正在后台运行一个长时间的进程(实际上是另一个 Python 脚本)。 我需要知道它何时完成。 我发现 Popen.poll() 始终返回 0,用于后台进程。是否有其他方法可以做到这一点?

p = subprocess.Popen("sleep 30 &", shell=True,
    stdout=subprocess.PIPE, stderr=subprocess.PIPE)
a = p.poll()
print(a)

上面的代码从不打印出None


1
你正在使用shell后台语法(),这使得子进程开始一个子子进程,然后退出自身 - 这就是为什么你得到0(进程完成)而不是None(仍在运行)。 - xjcl
3个回答

48

你不需要使用shell后台运行的&语法,因为subprocess将自己在后台运行进程。

只需正常运行命令,然后等待直到Popen.poll返回not None

import time
import subprocess

p = subprocess.Popen("sleep 30", shell=True)
# Better: p = subprocess.Popen(["sleep", "30"])

# Wait until process terminates
while p.poll() is None:
    time.sleep(0.5)

# It's done
print("Process ended, ret code:", p.returncode)

15

我认为您想要使用popen.wait()popen.communicate()命令。使用Communicate将获取您放入PIPE中的stdoutstderr数据。如果另一个项目是Python脚本,我建议避免运行shell=True调用,可以尝试这样做:

p = subprocess.Popen([python.call, "my", params, (go, here)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
(stdout, stderr) = p.communicate()
print(stdout)
print(stderr)

这些代码会阻塞主线程并等待其他进程完成,这可能不太好。如果您想要忙等待,那么可以将原始代码放入循环中。 (顺便说一下,您的原始代码对我来说打印了“None”)

以下是使用循环解决方案的示例:

p = subprocess.Popen([python.call, "my", params, (go, here)], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while p.poll() == None:
    # We can do other things here while we wait
    time.sleep(.5)
    p.poll()
(results, errors) = p.communicate()
if errors == '':
    return results
else:
    raise My_Exception(errors)

根据dbr的精彩回答,我清理了我的循环示例(完全忘记添加睡眠调用以避免过度切换)。 - Ian Burnette

10

你不应该在脚本末尾加上&符号来运行,因为Shell会复制你的进程并返回0退出代码。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接