在循环中打开多个gz文件时有没有办法阻止MemoryError?

时间:2018-02-17 15:41:52

标签: python garbage-collection out-of-memory

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

我的计算机中存储了一系列.gz文件(每个文件大到440 Mb)(如果你想用它们来尝试代码,它们是this directory中的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"))

,即当我分开打​​开每个文件时,即使它们的尺寸很大,我也不会遇到任何问题。

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

import gzip

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

现在是我遇到问题,更准确地说是MemoryError。我只是假设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失败

然后,考虑到我是一个聪明的女孩,我试着制作两个小窍门;第一个打开一个特定的文件(名称在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")

这是第一个脚本使用的file_open_and_process.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

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

提前谢谢你!

2 个答案:

答案 0 :(得分:3)

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

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

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 ,因为你不能让两个文件都存在于内存中。

master.py

现在,如果仍然无法解决某些(奇怪的)原因,只需执行2个流程并使用参数调用它们:

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

最后,将处理结果(必须更小)存储在结果文件中。

运行所有进程后,在MObject locatorObj = dagModifier.createNode("transform"); MObject locShapeObj = dagModifier.createNode("locator", locatorObj); dagModifier.renameNode(locatorObj, "root"); dagModifier.renameNode(locShapeObj, "rootShape"); 脚本中收集数据并继续。

答案 1 :(得分:2)

psc_aaa.gz的文件大小是未压缩的1,718,317,178字节。如果可能的话,一次一行地处理文件而不是内存:

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

输出(前几行):

1.119851|-89.91861|0.11|0.06|90|00042876-8955069 |12.467|0.018|0.021|359.4|12.131|0.025|0.026|224.7|11.963|0.023|0.025|133.7|AAA|222|111|000|666666|37.2|245|1329023254|0|0|1101364107|s|2000-09-22|64|302.951|-27.208|1.6|2451809.7124|1.07|1.18|0.81|12.481|0.014|12.112|0.028|11.98|0.012|332|251|sw|1|1|0|\N|\N|\N|\N|0|\N|59038|1357874|267
1.296576|-89.933235|0.14|0.14|73|00051117-8955596 |16.445|0.147|0.148|8.9|15.49|0.154|0.154|7.7|14.71|0.132|0.132|9.9|BBB|222|111|000|060616|13.6|290|1181038081|0|0|1085342201|s|2000-08-03|111|302.947|-27.194|2.6|2451759.8041|1.31|0.94|1.38|15.996|0.102|14.956|0.161|14.269|0.212|286|250|sw|1|1|0|\N|\N|\N|\N|0|\N|58104|1336392|267
3.373635|-89.964142|0.25|0.23|175|00132967-8957509 |16.601|0.134|0.135|8|16.005|0.185|0.185|5.7|15.512|0.212|0.212|5.3|BCC|222|111|000|060605|25.4|148|1085389169|0|0|1229087102|s|2000-09-02|55|302.939|-27.164|23.9|2451789.6258|0.85|1.1|0.92|16.909|0.316|16.458|0.573|15.476|0.335|175|229|sw|1|1|0|\N|\N|\N|\N|0|\N|66092|1520116|267
7.821089|-89.912903|0.12|0.07|0|00311706-8954464 |12.431|0.021|0.024|346.8|12.038|0.025|0.027|205.9|11.937|0.024|0.026|141.8|AAA|222|111|000|666666|41|237|1101364107|0|0|1127037907|s|2000-09-01|66|302.941|-27.215|-6.7|2451788.7241|1.02|1.11|1.41|12.419|0.008|12.03|0.032|11.912|0.034|354|245|se|1|1|U|0.3|4|15.2|13|1|\N|60459|1390557|267