Python:subprocess32 process.stdout.readline()等待时间
如果我使用例如“ls-Rlah/”运行下面的函数“run”,我会按照预期通过print语句立即获得输出Python:subprocess32 process.stdout.readline()等待时间,python,python-2.7,subprocess,Python,Python 2.7,Subprocess,如果我使用例如“ls-Rlah/”运行下面的函数“run”,我会按照预期通过print语句立即获得输出 import subprocess32 as subprocess def run(command): process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.ST
import subprocess32 as subprocess
def run(command):
process = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
try:
while process.poll() == None:
print process.stdout.readline()
finally:
# Handle the scenario if the parent
# process has terminated before this subprocess
if process.poll():
process.kill()
但是,如果我使用下面的python示例程序,它似乎会被困在process.poll()或process.stdout.readline()上,直到程序完成。我认为这是stdout.readline(),因为如果我将要输出的字符串数从10增加到10000(在示例程序中),或者在每次打印之后添加一个sys.stdout.flush(),run函数中的打印确实会执行
如何使子流程的输出更加实时
注意:我刚刚发现python示例程序在输出时不执行sys.stdout.flush(),是否有办法让子流程的调用方以某种方式强制执行
每5秒输出10个字符串的示例程序
#!/bin/env python
import time
if __name__ == "__main__":
i = 0
start = time.time()
while True:
if time.time() - start >= 5:
for _ in range(10):
print "hello world" + str(i)
start = time.time()
i += 1
if i >= 3:
break
您应该刷新脚本中的标准输出:
print "hello world" + str(i)
sys.stdout.flush()
当标准输出是一个终端时,标准输出是行缓冲的。但如果不是,则stdout是块缓冲的,您需要显式地刷新它
如果无法更改脚本的源代码,可以使用Python的-u
选项(在子流程中):
您的命令应该是:['python','-u','script.py']
通常,这种缓冲发生在用户空间中。没有通用的方法强制应用程序刷新其缓冲区:一些应用程序支持命令行选项(如Python),其他应用程序支持信号,其他应用程序不支持任何东西
一种解决方案可能是模拟一个伪终端,向程序提供“提示”,让它们以行缓冲模式运行。尽管如此,这并不是一个在所有情况下都有效的解决方案。对于python以外的其他东西,您可以尝试使用: unbuffer禁用从非交互式程序重定向程序输出时发生的输出缓冲。例如,假设您正在通过od运行fifo,然后再运行更多,以查看fifo的输出。 od-c/tmp/fifo |更多 在生成完整的输出页面之前,您不会看到任何内容。 您可以按如下方式禁用此自动缓冲: 正常情况下,unbuffer不会从stdin读取数据。这简化了在某些情况下使用unbuffer。要在管道中使用unbuffer,请使用-p标志。例子: 流程1 |解除缓冲-p流程2 |流程3 因此,在你的情况下:
run(["unbuffer",cmd])
文件中列出了一些注意事项,但这是另一种选择 在大多数系统上,命令行根据stdout是终端还是管道对行缓冲区或块缓冲区进行编程。在unixy系统上,父进程可以创建一个伪终端,以获得类似终端的行为,即使子进程不是真正从终端运行。您可以使用
pty
模块来创建伪终端,也可以使用pexpect
模块来简化对交互式程序的访问
如注释中所述,使用poll
读取行可能会导致数据丢失。一个例子是进程终止时留在标准输出管道中的数据。读取pty
与管道有点不同,您会发现当孩子关上时,您需要捕获IOError,以使其正常工作,如下面的示例所示
try:
import subprocess32 as subprocess
except ImportError:
import subprocess
import pty
import sys
import os
import time
import errno
print("running %s" % sys.argv[1])
m,s = (os.fdopen(pipe) for pipe in pty.openpty())
process = subprocess.Popen([sys.argv[1]],
stdin=s,
stdout=s,
stderr=subprocess.STDOUT)
s.close()
try:
graceful = False
while True:
line = m.readline()
print line.rstrip()
except IOError, e:
if e.errno != errno.EIO:
raise
graceful = True
finally:
# Handle the scenario if the parent
# process has terminated before this subprocess
m.close()
if not graceful:
process.kill()
process.wait()
即使使用它,我仍然得到相同的结果。注意:我将subprocess32与Python2.7.10process=subprocess.Popen(命令,stdout=subprocess.PIPE,stderr=subprocess.stdout)一起使用,并通过以下调用从进程中读取:while process.poll()==None:print process.stdout.readline()就像上面的例子一样。ahhh:)而不是执行打印过程。我对iter中的行(process.stdout.readline,b“”)执行了stdout.readline(),但读取行直到刷新缓冲区后才返回。根据stdout是终端还是管道,过程倾向于使用不同的缓冲区。您正在使用管道,因此子级将阻止缓冲区。请尝试使用
pty
模块中的伪终端,或使用为此类对象构建的pexpect
。1命令应该是POSIX上的列表(例如,“ls-Rlah/”.split()
)2。使用is None
代替==None
3<代码>打印行
将换行符加倍,使用打印行
(注意:逗号)来抑制第二个不必要的换行符4<代码>如果p.poll():p.kill()错误。看,我不知道,没有终端,它是块缓冲,有用的信息,谢谢!然而,我要寻找的是,有没有一种方法可以在非块缓冲区模式下调用子流程?谢谢,是的,这很有效!但是安德里亚,有没有更通用的方法?i、 e.如果进程不是python,那么我将被卡住。@Har:这适用于python在父进程中完成的缓冲。它确实(也不能)影响子流程。我们所说的那种缓冲完全是由程序本身或它所使用的库来完成的,内核在这里没有任何作用(因此我们不能将缓冲区大小从一个进程“转移”到另一个进程),在代码中乱丢垃圾很少是正确的答案,甚至在您无法控制的代码上也不可能。大多数程序应该只写标准输出,让父程序控制它的行或块是否被缓冲。除了在Windows上,Microsoft从未提供过好的pty解决方案。不要使用.poll()
(这样最终可能会丢失数据)。看见无关:如果process.poll()。不要使用.poll()==None
,如果您需要与None
进行比较,请使用.poll()为None
,您是对的!我尽可能地保留了原始代码,但在您的评论之后,我意识到我最好给出一个更完整的示例。谢谢。使用stdin=s
run(["unbuffer",cmd])
try:
import subprocess32 as subprocess
except ImportError:
import subprocess
import pty
import sys
import os
import time
import errno
print("running %s" % sys.argv[1])
m,s = (os.fdopen(pipe) for pipe in pty.openpty())
process = subprocess.Popen([sys.argv[1]],
stdin=s,
stdout=s,
stderr=subprocess.STDOUT)
s.close()
try:
graceful = False
while True:
line = m.readline()
print line.rstrip()
except IOError, e:
if e.errno != errno.EIO:
raise
graceful = True
finally:
# Handle the scenario if the parent
# process has terminated before this subprocess
m.close()
if not graceful:
process.kill()
process.wait()