我目前在进行一个使用相对较大的字典(大约800MB)的Python项目。我尝试使用pickle存储其中一个字典,但是出现了MemoryError。
在Python中,正确的文件保存方式是什么?我应该使用数据库吗?
我目前在进行一个使用相对较大的字典(大约800MB)的Python项目。我尝试使用pickle存储其中一个字典,但是出现了MemoryError。
在Python中,正确的文件保存方式是什么?我应该使用数据库吗?
Python标准shelve模块为持久化对象提供了类似字典的接口。它可以与许多数据库后端一起使用,并且不受RAM限制。与直接使用数据库相比,使用shelve
的优点是大部分现有代码保持不变。但这样做会以速度(与内存中的字典相比)和灵活性(与直接使用数据库相比)为代价。
shelf
不同的是,klepto
不需要将整个字典存储在单个文件中(当您只需要一个条目时,使用单个文件进行读写非常缓慢)。此外,与shelf
相比,klepto
可以存储几乎任何类型的Python对象,您可以将函数、lambda、类实例、套接字、多处理队列等存储到其中。
klepto
提供了一个字典抽象,用于向数据库编写内容,包括将文件系统视为数据库(即将整个字典写入单个文件,或将每个条目写入其自己的文件)。对于大型数据,我经常选择将字典表示为文件系统上的目录,并使每个条目成为一个文件。 klepto
还提供了各种缓存算法(如mru
,lru
,lfu
等),以帮助您管理内存中的缓存,并将使用算法来对转储和从档案后端进行加载。>>> from klepto.archives import dir_archive
>>> d = {'a':1, 'b':2, 'c':map, 'd':None}
>>> # map a dict to a filesystem directory
>>> demo = dir_archive('demo', d, serialized=True)
>>> demo['a']
1
>>> demo['c']
<built-in function map>
>>> demo
dir_archive('demo', {'a': 1, 'c': <built-in function map>, 'b': 2, 'd': None}, cached=True)
>>> # is set to cache to memory, so use 'dump' to dump to the filesystem
>>> demo.dump()
>>> del demo
>>>
>>> demo = dir_archive('demo', {}, serialized=True)
>>> demo
dir_archive('demo', {}, cached=True)
>>> # demo is empty, load from disk
>>> demo.load()
>>> demo
dir_archive('demo', {'a': 1, 'c': <built-in function map>, 'b': 2, 'd': None}, cached=True)
>>> demo['c']
<built-in function map>
>>>
klepto
还提供了使用内存映射文件后端进行快速读写的功能。还有其他标志,例如compression
,可用于进一步自定义数据存储方式。使用(MySQL等)数据库作为后端与使用文件系统一样容易(完全相同的接口)。您可以使用标志cached=False
完全关闭内存缓存,并直接从磁盘或数据库中读取和写入。
>>> from klepto.archives import dir_archive
>>> # does not hold entries in memory, each entry will be stored on disk
>>> demo = dir_archive('demo', {}, serialized=True, cached=False)
>>> demo['a'] = 10
>>> demo['b'] = 20
>>> demo['c'] = min
>>> demo['d'] = [1,2,3]
klepto
请前往此处:https://github.com/uqfoundation。也许你可以使用sqlite3?除非你的Python版本真的很老,否则它应该是可用的:https://docs.python.org/2/library/sqlite3.html
我没有检查过sqlite3的限制,并且我对它在你的情况下的有用性一无所知,但值得一试。
当您将整个数据结构进行pickle时,会受到系统RAM的限制。但是,您可以分块处理。
streaming-pickle
看起来是pickle文件类对象大于内存的解决方案。
由于它是一个字典,您可以将其转换为键值对列表 ([(k, v)]
)。然后,您可以使用任何技术(如 pickle)将每个元组序列化为字符串,并逐行将它们存储到文件中。这样,并行处理、检查文件内容等也更容易。
有一些库允许您使用单个对象进行流式传输,但在我看来,这只会使事情变得更加复杂。仅按行存储就可以减少很多麻烦。
head
等工具进行检查,可以更节省空间,并且更难损坏。 - Enno Shioji
json
模块是一个可以轻松尝试的替代方案(import json; json.dumps(mydict)
),看看是否会出现相同的错误。 - Tim Pietzcker