Python 在循环中打开许多gz文件时,是否有任何方法可以防止内存错误?

Python 在循环中打开许多gz文件时,是否有任何方法可以防止内存错误?,python,garbage-collection,out-of-memory,Python,Garbage Collection,Out Of Memory,考虑到单独打开一系列大型.gz文件时不会产生错误,如何避免在循环中打开一系列大型.gz文件时出现内存错误? 我的计算机中存储了一系列的.gz文件(每个文件的大小为440MB)(如果您想用它们来尝试代码,它们就是其中的psc文件)。我想打开第一个并用它做一些操作,然后打开第二个并做一些操作,依此类推 当我执行这个代码时 import gzip files=['thing1.gz', 'thing2.gz'] x=list(gzip.open(files[0],"r")) import gzip

考虑到单独打开一系列大型.gz文件时不会产生错误,如何避免在循环中打开一系列大型.gz文件时出现内存错误?

我的计算机中存储了一系列的.gz文件(每个文件的大小为440MB)(如果您想用它们来尝试代码,它们就是其中的psc文件)。我想打开第一个并用它做一些操作,然后打开第二个并做一些操作,依此类推

当我执行这个代码时

import gzip

files=['thing1.gz', 'thing2.gz']
x=list(gzip.open(files[0],"r"))
import gzip

files=['thing1.gz', 'thing2.gz']
x=list(gzip.open(files[1],"r"))
,或此代码

import gzip

files=['thing1.gz', 'thing2.gz']
x=list(gzip.open(files[0],"r"))
import gzip

files=['thing1.gz', 'thing2.gz']
x=list(gzip.open(files[1],"r"))
,也就是说,当我分别打开每个文件时,即使它们的大小很大,我也不会遇到任何问题

但我是一个懒惰的人,所以我想对许多文件执行此操作,而不必手动使用不同的文件执行脚本。所以我需要一个for循环,就像这样

import gzip

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=list(gzip.open(current_file,"r"))
现在我遇到了一个问题,更准确地说是一个记忆错误。我只是假设x变量将被重命名,并且上一个文件的任何剩余部分都将被覆盖

我已经搜索了许多类似的问题(我认为这不是重复的,因为所有这些类似的问题都是用一种或另一种方法解决的,但我的问题无法解决)

为了节省您的时间,以下是我尝试过但未能解决问题的可能解决方案:

失败的解决方案#1

import gzip

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=list(gzip.open(current_file,"r"))
    del x
这不起作用,也不能像另一个线程中建议的那样等待一段时间

import gzip
import time

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=list(gzip.open(current_file,"r"))
    time.sleep(120)
    del x
无论是创建一个删除所有不重要变量的函数还是在另一个线程中建议的函数(据我所知,它与del是一样的,那么为什么这应该有效呢?)

失败的解决方案#2

关闭文件是另一个不起作用的想法

import gzip

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=gzip.open(current_file,"r")
    y=list(x)
    x.close()
    del y
失败的解决方案#3

强制使用垃圾收集器(正如在许多类似问题中所说的那样)也会因为某些原因(可能我还不了解它是如何工作的)而导致工作不好

因为这是垃圾收集器的一个糟糕用法(我不编辑前面的代码,因为我在一些线程中看到它是以这种方式编写的,这可能有助于理解一些人)

遗憾的是,新代码仍然不起作用

import gzip
import gc

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=list(gzip.open(current_file,"r"))
    x=None
    gc.collect()
失败的解决方案#4

然后,我认为我是一个聪明的女孩,我试着做了两个片段;第一个打开一个特定的文件(谁的名字在一个显然也必须打开的txt文档中指定)并对该文件进行一些操作,而另一个只是使用当前文件的名称创建该txt文件的文件,该文件必须由另一个脚本打开并为该文件运行(在循环中)。也就是说,我把剧本一分为二;一个打开de文件,另一个创建循环以打开所有文件。这对我来说似乎是合乎逻辑的,因为当我单独打开每个文件时,没有问题。我只需要用另一个脚本按顺序自动打开它们!但事实证明,这也不起作用

import gzip

def open_and_process(file):
    return list(gzip.open(current_file,"r"))

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=open_and_process(current_file)
    del x
这是在另一个脚本上循环的脚本:

import os

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    temporary_file=open("temp.txt","w")
    temporary_file.write(current_file)
    temporary_file.close()
    execfile("file_open_and_process.py")

os.remove("temp.txt")
这是第一个脚本使用的文件\u open\u和\u process.py:

import gzip

current_file=open("temp.txt","r").read()
x=list(gzip.open(current_file,"r"))
失败的解决方案#5

另一个想法是将所有文件打开和工作作为一个函数,然后在循环中调用它,这样变量就可以作为局部变量而不是全局变量存储在内存中,正如前面所说的那样。但这也不行

import gzip

def open_and_process(file):
    return list(gzip.open(current_file,"r"))

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=open_and_process(current_file)
    del x
对于我来说,理解为什么会发生这种情况非常重要,或者至少得到一个允许我对代码进行很少更改的解决方案(与这些玩具示例相比,代码非常复杂)


提前谢谢你

处理速度必须非常快,除非您强制垃圾收集器(或者垃圾收集器未达到其收集阈值),否则垃圾收集器无法运行

我无法用您的数据测试您的示例,但强制调用的最后一个片段(这是正确的操作)错误地使用了垃圾收集器:

import gzip
import gc

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=list(gzip.open(current_file,"r"))
    gc.collect()
调用
gc.collect()
时,您收集的不是当前的
x
,而是上一个。在调用垃圾收集器之前,必须
del x
,因为内存中不能同时存在这两个文件

for current_file in files:
    x=list(gzip.open(current_file,"r"))
    # work
    x = None  # or del x
    gc.collect()  # now x will surely be collected
现在,如果出于某种(wierd)原因,这仍然不起作用,只需执行两个进程并使用参数调用它们:

master.py
包含:

import subprocess
for current_file in files:
   subprocess.check_call(["python","other_script.py",current_file])
other_file.py
将包含以下处理:

import sys,gzip
with gzip(open(sys.argv[1])) as f:
   x = list(f)
   # rest of your processing
最后,将处理结果(必须更小)存储在结果文件中


所有进程运行后,在
master.py
脚本中收集数据并继续。

psc_aaa.gz的文件大小为1718317178字节未压缩。如果可能,请逐行处理文件,而不是一次在内存中处理所有文件:

import gzip

files=['psc_aaa.gz']
for current_file in files:
    with gzip.open(current_file,'rt') as f:
        for line in f:
            print(line,end='')
输出(前几行):


您需要立即将整个文件存储在列表中,还是只需迭代文件对象?@JesseBakker不完全必要。我想知道在那种情况下的选择。但是,因为我觉得这对未来来说是一件重要的事情,所以我真的需要一次检查所有的文件。我可以单独打开它们,因此我希望有一种方法可以逐个从内存中删除上一个。仅供参考,第一个文件psc_aaa.gz的未压缩文件大小为1718317178字节。如果要打开的所有文件的未压缩大小超过计算机内存量,您将无法将所有数据存储在内存中。
list()
构造函数获取一组对象,并将所有对象存储在内存中。因此,如果您的文件大于内存量,那么创建
list()
将永远无法工作。您需要以较小的块(例如,一次一行)处理数据。@DanielPryden但正如我所说,我不想将所有数据存储在内存中。我只想存储一个文件中的数据,对它做一些处理,然后删除它并传递到下一个文件。我可以手动操作,