我有一个用Python编写的程序,在某些时候会创建一个子进程,然后必须在"实时"中得到它的std输出。通过一个文件(该过程需要一段时间,并且在它仍在运行时需要一些输出)。 问题是,有时,输出的一大块会丢失(实际上是从一开始就开始的一个块)。代码如下所示:
import subprocess
import tempfile
import time
..
tf_out = tempfile.TemporaryFile()
tf_err = tempfile.TemporaryFile()
tf_in = tempfile.TemporaryFile()
tf_in.write(some_stdin)
tf_in.seek(0)
# create the process
process = subprocess.Popen(command, shell=True,
stdin=tf_in,
stdout=tf_out,
stderr=tf_err)
running = True
while running:
# last iteration if process ended
if process.poll() is not None:
running = False
# read output
tf_out.seek(0) # 1
stdout = tf_out.read() # 2
# do something with the partial output
do_something(stdout)
time.sleep(0.1)
tf_out.close()
tf_err.close()
tf_in.close()
..
我想知道问题是否可能在# 1
和# 2
之间,如果:子进程写入内容,然后在# 1
寻求归零,另一个写入开始由于搜索(错误的一个)而在零处,最后在# 2
处的读取没有看到第一次写入。如果这是问题,任何想法如何做?
提前致谢!
答案 0 :(得分:0)
从Popen获取实时数据非常挑剔。此外,良好的旧print
通常也会缓冲输出。
以下内容改编自另一个SO问题。它已设置好,您可以运行它。
#!/usr/bin/env python
# adapted from http://stackoverflow.com/questions/2804543/read-subprocess-stdout-line-by-line
import subprocess, sys, time
def test_proc(cmd):
start = time.time()
print 'COMMAND:',cmd
proc = subprocess.Popen(
cmd,
shell=True,
stdout=subprocess.PIPE,
)
for line in iter(proc.stdout.readline, ''):
sys.stdout.write('{:.2f} {}\n'.format(
time.time() - start,
line.rstrip()
))
sys.stdout.flush()
if __name__=='__main__':
test_proc('ping -c3 8.8.8.8')
COMMAND: ping -c3 8.8.8.8
0.05 PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
0.05 64 bytes from 8.8.8.8: icmp_seq=1 ttl=43 time=49.0 ms
1.05 64 bytes from 8.8.8.8: icmp_seq=2 ttl=43 time=46.8 ms
2.05 64 bytes from 8.8.8.8: icmp_seq=3 ttl=43 time=49.1 ms
2.05
2.05 --- 8.8.8.8 ping statistics ---
2.05 3 packets transmitted, 3 received, 0% packet loss, time 2003ms
2.05 rtt min/avg/max/mdev = 46.826/48.334/49.143/1.097 ms
左侧的数字是自命令启动以来的秒数。由于ping
命令每秒发送一次数据包,因此会验证数据是否实时处理。当ping
开始时,两个“0.05”行是吐出的。下一行是在第二行之后,当收到第一个ping响应时。在时间2.05,收到最后一个响应,ping
输出一个页脚。
非常方便!
答案 1 :(得分:0)
我只是弄清楚如何解决这个问题。一个简单的解决方案是打开临时文件两次,一个传递给子进程,另一个实际执行读取。此外,您可以使用tempfile模块创建一个命名的临时文件,如下所示:
import tempfile
tf_in = tempfile.TemporaryFile()
tf_in.write(some_stdin)
tf_in.seek(0)
tf_out = tempfile.NamedTemporaryFile()
tf_out2 = open(tf_out.name, 'r')
tf_err = tempfile.NamedTemporaryFile()
tf_err2 = open(tf_err.name, 'r')
# create the process
process = subprocess.Popen(command, shell=True,
stdin=tf_in,
stdout=tf_out,
stderr=tf_err)
# same loop but reading from tf_out2 and tf_err2
# close files
使用两个文件对象进行写入和读取可以解决问题。
无论如何,谢谢你的答案!