我需要解析外部程序(第三方,我无法控制它)产生的输出,这会产生大量数据。由于输出的大小大大超过可用内存,我想在进程运行时解析输出 并从内存中删除已经处理过的数据。
到目前为止,我做了类似的事情:
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))
但它被卡住了,无法理解为什么。
所以我想知道实现这一目标的最佳方法是什么?有哪些问题需要注意?
答案 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))