在一个循环中打开多个gz文件时,有没有什么方法可以防止内存错误?

2024-10-01 09:25:39 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

当我执行这段代码时

import gzip

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

,或此代码

^{pr2}$

,也就是说,当我分开打开每个文件时,即使它们的大小很大,我也不会遇到任何问题。在

但我是一个懒惰的人,所以我想对许多文件都这样做,而不必手动执行另一个文件的脚本。所以我需要一个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是一样的,所以为什么它应该起作用呢?)。在

import gzip

def clearall():
    not_variables=[var for var in globals() if (var[:2],var[-2:])==("__","__")]
    white_list=["files","gzip","clearall"]
    black_list=[var for var in globals() if var not in white_list+not_variables]
    for var in black_list:
        del globals()[var]

files=['thing1.gz', 'thing2.gz']
for current_file in files:
    x=list(gzip.open(current_file,"r"))
    clearall()

失败的解决方案#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"))
    gc.collect()

因为Jean-François Fabre pointed这是垃圾收集器的一个坏用法(我不编辑前面的代码,因为我在一些线程中看到它是以这种方式编写的,所以我不编辑前面的代码,因为可能有助于某些人理解它)。在

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

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

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

脚本的另一个循环是:

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")

这是打开的文件_进程.py由第一个脚本使用:

import gzip

current_file=open("temp.txt","r").read()
x=list(gzip.open(current_file,"r"))

失败的解决方案#5

另一个想法是将所有打开和工作的文件作为一个函数,然后在循环中调用它,以便变量作为局部变量而不是全局变量存储在内存中,就像前面说的in yet another thread。但这也不管用。在

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

对于我来说,理解为什么会发生这种情况非常重要,或者至少找到一个解决方案,让我在代码中更改很少(与这些玩具示例相比,代码非常复杂)。在

提前谢谢你!在


Tags: 文件代码inimportforvarfilesopen
2条回答

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='')

输出(前几行):

^{pr2}$

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

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

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,因为内存中不能同时存在这两个文件。在

^{pr2}$

现在,如果由于某种原因(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脚本中的数据并继续。在

相关问题 更多 >