Pickle转储巨大的文件没有内存错误

时间:2013-07-07 14:31:11

标签: python memory file-io pickle

我有一个程序,我基本上根据已知的事情调整某些事情发生的概率。我的数据文件已经保存为Dictionary.txt中的pickle Dictionary对象。问题是,每次运行程序时它都会拉入Dictionary.txt,将其转换为字典对象,进行编辑并覆盖Dictionary.txt。这是相当大的内存密集型,因为Dictionary.txt是123 MB。当我转储我得到MemoryError时,当我把它拉进来时,一切似乎都很好。

  • 是否有更好(更有效)的编辑方式? (或许不必每次都覆盖整个文件)

  • 有没有办法可以调用垃圾收集(通过gc模块)? (我已经通过gc.enable())自动启用了它

  • 我知道除了readlines()之外你还可以逐行阅读。当我在程序中已经有一个完整的Dictionary对象文件时,有没有办法逐行逐行编辑字典。

  • 还有其他解决方案吗?

感谢您的时间。

9 个答案:

答案 0 :(得分:12)

我是名为klepto的软件包的作者(也是dill的作者)。 klepto用于以非常简单的方式存储和检索对象,并为数据库,内存缓存和磁盘上的存储提供简单的字典界面。下面,我展示了将大对象存储在"目录存档"中,这是一个文件系统目录,每个条目有一个文件。我选择序列化对象(速度较慢,但​​使用dill,因此您可以存储几乎所有对象),并选择缓存。使用内存缓存使我能够快速访问目录存档,而无需将整个存档存储在内存中。与数据库或文件交互可能很慢,但与内存交互很快......您可以根据需要从存档中填充内存缓存。

>>> import klepto
>>> d = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> d
dir_archive('stuff', {}, cached=True)
>>> import numpy
>>> # add three entries to the memory cache
>>> d['big1'] = numpy.arange(1000)
>>> d['big2'] = numpy.arange(1000)
>>> d['big3'] = numpy.arange(1000)
>>> # dump from memory cache to the on-disk archive
>>> d.dump()
>>> # clear the memory cache
>>> d.clear()
>>> d
dir_archive('stuff', {}, cached=True)
>>> # only load one entry to the cache from the archive
>>> d.load('big1')
>>> d['big1'][-3:]
array([997, 998, 999])
>>> 

klepto提供对大量存储的快速灵活访问,如果存档允许并行访问(例如某些数据库),那么您可以并行读取结果。在不同的并行流程或不同的机器上共享结果也很容易。在这里,我创建了第二个存档实例,指向同一个目录存档。在两个对象之间传递密钥很容易,并且与不同的进程没有区别。

>>> f = klepto.archives.dir_archive('stuff', cached=True, serialized=True)
>>> f
dir_archive('stuff', {}, cached=True)
>>> # add some small objects to the first cache  
>>> d['small1'] = lambda x:x**2
>>> d['small2'] = (1,2,3)
>>> # dump the objects to the archive
>>> d.dump()
>>> # load one of the small objects to the second cache
>>> f.load('small2')
>>> f       
dir_archive('stuff', {'small2': (1, 2, 3)}, cached=True)

您还可以从各种级别的文件压缩中选择,以及是否 您希望文件是内存映射的。有很多不同 选项,包括文件后端和数据库后端。界面 但是,它是相同的。

关于有关垃圾收集和编辑字典部分的其他问题,两者都可以使用klepto,因为您可以单独加载和删除内存缓存中的对象,转储,加载和同步存档后端,或任何其他字典方法。

请在此处查看更长的教程:https://github.com/mmckerns/tlkklp

在此处获取kleptohttps://github.com/uqfoundation

答案 1 :(得分:9)

我遇到了同样的问题。我使用joblib并完成了工作。如果有人想知道其他可能性。

将模型保存到磁盘

from sklearn.externals import joblib
filename = 'finalized_model.sav'
joblib.dump(model, filename)  

一段时间后......从磁盘加载模型

loaded_model = joblib.load(filename)
result = loaded_model.score(X_test, Y_test) 

print(result)

答案 2 :(得分:3)

我有内存错误并使用protocol = 2解决了它:

cPickle.dump(obj, file, protocol=2)

答案 3 :(得分:2)

如果您的键和值是字符串,则可以使用Python标准库中提供的嵌入式持久键值存储引擎之一。 anydbm模块文档中的示例:

import anydbm

# Open database, creating it if necessary.
db = anydbm.open('cache', 'c')

# Record some values
db['www.python.org'] = 'Python Website'
db['www.cnn.com'] = 'Cable News Network'

# Loop through contents.  Other dictionary methods
# such as .keys(), .values() also work.
for k, v in db.iteritems():
    print k, '\t', v

# Storing a non-string key or value will raise an exception (most
# likely a TypeError).
db['www.yahoo.com'] = 4

# Close when done.
db.close()

答案 4 :(得分:2)

您是否尝试使用流式传感器:https://code.google.com/p/streaming-pickle/

我刚刚通过切换到流式泡菜解决了类似的内存错误。

答案 5 :(得分:2)

这个怎么样?

import cPickle as pickle
p = pickle.Pickler(open("temp.p","wb")) 
p.fast = True 
p.dump(d) # d could be your dictionary or any file

答案 6 :(得分:1)

我最近遇到了这个问题。在尝试使用ASCII和二进制协议2进行cpickle之后,我发现我的sci-kit中的SVM学习了20+ gb数据,因为内存错误而没有进行酸洗。然而,莳萝包似乎解决了这个问题。 Dill不会为字典创建许多改进,但可能有助于流式传输。它旨在通过网络流式传输腌制字节。

import dill

with open(path,'wb') as fp:
    dill.dump(outpath,fp)
    dill.load(fp)

如果效率问题,请尝试加载/保存到数据库。在这种情况下,您的存储解决方案可能是一个问题。在1200 MB的熊猫应该没事。但是,如果机器内存有限,SQL提供快速,优化的数据包操作,通常具有多线程支持。 我的poly kernel svm已保存。

答案 7 :(得分:1)

上述答案都不适合我。我最终使用了Hickle,它是基于HDF5的泡菜的替代品。它将数据保存到HDF5文件,而不是将其保存到pickle。对于大多数用例而言,API是相同的,并且它具有一些非常酷的功能,例如压缩。

pip install hickle

示例:

# Create a numpy array of data
array_obj = np.ones(32768, dtype='float32')

# Dump to file
hkl.dump(array_obj, 'test.hkl', mode='w')

# Load data
array_hkl = hkl.load('test.hkl')

答案 8 :(得分:1)

这看起来似乎微不足道,但如果不是,请尝试使用64位Python。