从Python子进程(Popen)丢失一些std输出读数

时间:2014-07-07 18:02:43

标签: python python-2.7 subprocess stdout

我有一个用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处的读取没有看到第一次写入。如果这是问题,任何想法如何做?

提前致谢!

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

使用两个文件对象进行写入和读取可以解决问题。

无论如何,谢谢你的答案!