在执行和清除内存时解析子进程的输出(Python 2.7)

时间:2013-04-03 11:24:32

标签: python subprocess popen

我需要解析外部程序(第三方,我无法控制它)产生的输出,这会产生大量数据。由于输出的大小大大超过可用内存,我想在进程运行时解析输出 并从内存中删除已经处理过的数据。

到目前为止,我做了类似的事情:

import subprocess

p_pre = subprocess.Popen("preprocessor",stdout = subprocess.PIPE) 
# preprocessor is an external bash script that produces the input for the third-party software
p_3party = subprocess.Popen("thirdparty",stdin = p_pre.stdout, stdout = subprocess.PIPE)

(data_to_parse,can_be_thrown) = p_3party.communicate()

parsed_data = myparser(data_to_parse)

当“第三方”输出足够小时,这种方法有效。但正如Python文档中所述:

  

读取的数据缓冲在内存中,因此如果数据量很大或无限制,请不要使用此方法。

我认为更好的方法(实际上可以让我节省一些时间), 将是在生成时开始处理data_to_parse, 并且正确完成解析后,“清除”data_to_parse删除 已经解析过的数据。

我也尝试使用for循环,如:

parsed_data=[]
for i in p_3party.stdout:
    parsed_data.append(myparser(i))

但它被卡住了,无法理解为什么。

所以我想知道实现这一目标的最佳方法是什么?有哪些问题需要注意?

2 个答案:

答案 0 :(得分:1)

您可以使用subprocess.Popen()创建一个用于读取行的蒸汽。

import subprocess

stream = subprocess.Popen(stdout=subprocess.PIPE).stdout

for line in stream:
    #parse lines as you recieve them.
    print line

您可以将这些行传递给myparser()方法,或者将它们附加到列表中,直到您准备好使用它们为止。


在您的情况下,使用两个子流程,它将工作如下:

import subprocess

def method(stream, retries=3):
    while retries > 0:
        line = stream.readline()
        if line:
            yield line
        else:
            retries -= 1

pre_stream = subprocess.Popen(cmd, stdout=subprocess.PIPE).stdout
stream = subprocess.Popen(cmd, stdin=pre_stream, stdout=subprocess.PIPE).stdout

for parsed in method(stream):
    # do what you want with the parsed data.
    parsed_data.append(parsed)

答案 1 :(得分:1)

for i in p_3party.stdout:中迭代文件使用预读缓冲区。使用管道时readline()方法可能更可靠 - AFAIK逐字符读取。

while True:
    line = p_3party.stdout.readline()
    if not line:
        break
    parsed_data.append(myparser(line))