Python Popen.communicate()内存限制的替代方案?

21 投票
3 回答
6431 浏览
提问于 2025-04-16 22:33

我有一段Python代码(运行在2.7版本上),当我处理一些大文件(几GB)时,会出现MemoryError的错误:

myProcess = Popen(myCmd, shell=True, stdout=PIPE, stderr=PIPE)
myStdout, myStderr = myProcess.communicate()
sys.stdout.write(myStdout)
if myStderr:
    sys.stderr.write(myStderr)

在查看关于Popen.communicate()的文档时,我发现这里面有一些缓冲的处理:

注意 读取的数据会在内存中进行缓冲,所以如果数据量很大或者没有限制,就不要使用这个方法。

有没有办法禁用这个缓冲,或者在进程运行时定期清理缓存呢?

在Python中,我应该使用什么其他方法来运行一个命令,以便将几GB的数据流输出到stdout

我还需要处理输出和错误流。

3 个回答

0

对于那些在使用 Popen 后,应用程序会在一段时间后卡住的情况,请看看我下面的例子:

一个简单的规则,如果你不打算使用 stderrstdout 这两个输出流,那么就不要在 Popen 的参数中传递或初始化它们!因为它们会不断填满,导致你遇到很多麻烦。

如果你在某个时间段内需要使用这些输出流,并且需要让进程继续运行,那么你可以随时关闭这些输出流。

try:
    p = Popen(COMMAND, stdout=PIPE, stderr=PIPE)
    # After using stdout and stderr
    p.stdout.close()
    p.stderr.close()
except Exception as e:
    pass
5

如果我需要读取这么大一段输出,我可能会选择在创建进程的时候把它发送到一个文件里。

with open(my_large_output_path, 'w') as fo:
    with open(my_large_error_path, 'w') as fe:
        myProcess = Popen(myCmd, shell=True, stdout=fo, stderr=fe)

补充一下:如果你需要实时查看输出,可以尝试创建一个像文件一样的对象,然后把它传给标准输出和标准错误输出。(不过我还没试过这个。)这样的话,你就可以在数据写入的同时从这个对象中读取(查询)内容。

8

我想我找到了解决办法:

myProcess = Popen(myCmd, shell=True, stdout=PIPE, stderr=PIPE)
for ln in myProcess.stdout:
    sys.stdout.write(ln)
for ln in myProcess.stderr:
    sys.stderr.write(ln)

这个方法似乎能让我减少内存使用,从而顺利完成任务。

更新

我最近发现了一种更灵活的方式来处理Python中的数据流,使用线程。有趣的是,Python在这方面表现得很差,而shell脚本却能轻松做到!

撰写回答