Python 从子流程获取进度消息

Python 从子流程获取进度消息,python,subprocess,Python,Subprocess,我想开始一个需要几分钟才能完成的程序。在此期间,我想阅读程序的进度消息(打印在标准输出上)。问题是我找不到一种方法在运行期间读取它的输出 我找到的唯一读取程序输出的函数是Popen.communicate(),但此方法会等到进程完成。因此,不可能以一种特殊的格式化方式获取进度并使其对用户可见 有没有可能用另一种方法 当我用脚本运行带有subprocess.popen的进程时,我会在屏幕上看到程序的输出。有可能把它藏起来吗?(Ubuntu 10.10,普通终端)您可以对子进程的状态进行轮询,并保持

我想开始一个需要几分钟才能完成的程序。在此期间,我想阅读程序的进度消息(打印在标准输出上)。问题是我找不到一种方法在运行期间读取它的输出

我找到的唯一读取程序输出的函数是
Popen.communicate()
,但此方法会等到进程完成。因此,不可能以一种特殊的格式化方式获取进度并使其对用户可见

有没有可能用另一种方法


当我用脚本运行带有
subprocess.popen
的进程时,我会在屏幕上看到程序的输出。有可能把它藏起来吗?(Ubuntu 10.10,普通终端)

您可以对子进程的状态进行轮询,并保持输出行

p = subprocess.Popen('ls;sleep 10', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

rc = p.poll()
while rc != 0:
    while True:
        line = p.stdout.readline()
        if not line:
            break
        print line
    rc = p.poll()

assert rc == 0

最简单的方法是使用关键字参数调用Popen
stdout=subprocess.PIPE

p = subprocess.Popen(["ls"], stdout=subprocess.PIPE)
while True:
    line = p.stdout.readline()
    if not line:
        break
    print line

要了解这一点,这里有两个示例脚本。将它们放在同一个目录中并运行
python superprint.py

printandwait.py:

import time
import sys
print 10
sys.stdout.flush()
time.sleep(10)
print 20
sys.stdout.flush()
superprint.py:

import subprocess
import sys
p = subprocess.Popen(["python printandwait.py"], shell=True, stdout=subprocess.PIPE)
while True:
    print "Looping"
    line = p.stdout.readline()
    if not line:
        break
    print line.strip()
    sys.stdout.flush()

这当然是可能的:我的包就是这样做的,在一个子进程下生成
gpg
(Gnu隐私保护)。在一般情况下,需要为子流程stdout和stderr指定
subprocess.PIPE
;然后创建两个单独的线程,将子进程stdout和stderr读取到您喜欢的任何位置

python gnupg
的情况下,当
gpg
进程运行时(不等待它完成),会读取来自gpg的状态消息并对其执行操作

基本上,伪代码是

process = subprocess.Popen(..., stdout=subprocess.PIPE, stderr=subprocess.PIPE)
stderr = process.stderr
rr = threading.Thread(target=response_reader_func, args=(process.stderr,))
rr.setDaemon(True)
rr.start()

dr = threading.Thread(target=data_reader_func, args=(process.stdout,))
dr.setDaemon(True)
dr.start()

dr.join()
rr.join()
process.wait()

reader函数通常是一个封闭类的方法,它根据所读取的内容做正确的事情(在您的情况下,以某种方式更新进度信息)。

如果在您打破while循环后一些数据到达,该怎么办?@Neo:他的示例在EOF中断,这意味着在此之后无法再到达更多数据。但是,为了回答您的问题:如果您不继续读取标准输出管道,缓冲区可能会填满,子进程将阻止尝试写入标准输出。它将在p.stdout中等待您稍后使用。但是,readline调用将被阻止,直到新输入到达或管道关闭。添加了一些示例脚本。您可以对iter中的行(p.stdout.readline,b'')使用
:打印行,
,而不是
while
-循环。