Rom*_*uin 5 python memory pickle
我有一个python的pickle对象,它生成一个180 Mb的文件.当我取消它时,内存使用量会爆炸到2或3Gb.你有类似的经历吗?这是正常的吗?
对象是包含字典的树:每个边是一个字母,每个节点都是一个潜在的单词.因此,要存储一个单词,您需要的边数与该单词的长度一样多.所以,第一级是最多26个节点,第二个是26 ^ 2,第三个是26 ^ 3等...对于每个节点都是一个单词我有一个属性指向关于单词的信息(动词,名词,定义等...).
我有最多约40个字符的单词.我有大约五十万条款.一切顺利,直到我腌制(使用简单的cpickle转储):它提供180 Mb文件.我在Mac OS上,当我取消这些180 Mb时,操作系统会给python进程提供2或3 Gb的"内存/虚拟内存":(
我没有在这棵树上看到任何递归:边缘的节点本身就是一个数组数组.不涉及递归.
我有点卡住:这些180 Mb的加载大约是20秒(没有谈到内存问题).我不得不说我的CPU不是那么快:核心i5,1.3Ghz.但我的硬盘是ssd.我只有4Gb的内存.
要在我的树中添加这500 000个单词,我会阅读大约7 000个文件,每个文件包含大约100个单词.这个读取使得mac os分配的内存高达15 Gb,主要是在虚拟内存上:(我一直在使用"with"语句确保关闭每个文件,但实际上并没有帮助.阅读文件带走对于40 Ko,0.2秒.对我来说似乎很长.将它添加到树上要快得多(0.002秒).
最后我想创建一个对象数据库,但我猜python并不适合.也许我会去MongoDB :(
class Trie():
"""
Class to store known entities / word / verbs...
"""
longest_word = -1
nb_entree = 0
def __init__(self):
self.children = {}
self.isWord = False
self.infos =[]
def add(self, orthographe, entree):
"""
Store a string with the given type and definition in the Trie structure.
"""
if len(orthographe) >Trie.longest_word:
Trie.longest_word = len(orthographe)
if len(orthographe)==0:
self.isWord = True
self.infos.append(entree)
Trie.nb_entree += 1
return True
car = orthographe[0]
if car not in self.children.keys():
self.children[car] = Trie()
self.children[car].add(orthographe[1:], entree)
Run Code Online (Sandbox Code Playgroud)
Python 对象,特别是在 64 位机器上,非常大。当 pickle 时,对象会获得非常紧凑的表示形式,适合磁盘文件。这是一个拆解的 pickle 的示例:
>>> pickle.dumps({'x':'y','z':{'x':'y'}},-1)
'\x80\x02}q\x00(U\x01xq\x01U\x01yq\x02U\x01zq\x03}q\x04h\x01h\x02su.'
>>> pickletools.dis(_)
0: \x80 PROTO 2
2: } EMPTY_DICT
3: q BINPUT 0
5: ( MARK
6: U SHORT_BINSTRING 'x'
9: q BINPUT 1
11: U SHORT_BINSTRING 'y'
14: q BINPUT 2
16: U SHORT_BINSTRING 'z'
19: q BINPUT 3
21: } EMPTY_DICT
22: q BINPUT 4
24: h BINGET 1
26: h BINGET 2
28: s SETITEM
29: u SETITEMS (MARK at 5)
30: . STOP
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,它非常紧凑。如果可能的话,什么都不重复。
然而,在内存中,对象由相当数量的指针组成。我们来问Python一个空字典有多大(64位机器):
>>> {}.__sizeof__()
248
Run Code Online (Sandbox Code Playgroud)
哇!空字典248 字节!请注意,字典预先分配了最多可容纳八个元素的空间。但是,即使字典中有一个元素,您也会付出相同的内存成本。
类实例包含一个字典来保存实例变量。您的尝试为孩子们准备了一本额外的字典。因此,每个实例花费近 500 字节。通过估计 2-4 百万个 Trie 对象,您可以轻松查看内存使用情况的来源。
__slots__您可以通过向 Trie添加 a 来消除实例字典来稍微缓解这一问题。通过这样做,您可能会节省大约 750MB(我的猜测)。它会阻止您向 Trie 添加更多变量,但这可能不是一个大问题。
| 归档时间: |
|
| 查看次数: |
4764 次 |
| 最近记录: |