Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python内存序列化_Python_Class_Serialization_Memory Management_Pickle - Fatal编程技术网

Python内存序列化

Python内存序列化,python,class,serialization,memory-management,pickle,Python,Class,Serialization,Memory Management,Pickle,我想知道是否有人知道下面的答案 我正在使用Python构建一个基于字符的后缀树。树中有超过1100万个节点,可容纳大约3GB的内存。通过使用slot类方法而不是Dict方法,这比7GB有所下降 当我序列化树(使用最高协议)时,生成的文件要小上百倍 当我重新加载pickle文件时,它再次消耗3GB内存。这额外的开销是从哪里来的,是不是与python处理类实例的内存引用有关 更新 感谢拉斯曼斯和古尔奇的解释和建议。我使用树作为文本语料库上信息检索接口的一部分 我最初将子项(最多30个)存储为Nump

我想知道是否有人知道下面的答案

我正在使用Python构建一个基于字符的后缀树。树中有超过1100万个节点,可容纳大约3GB的内存。通过使用slot类方法而不是Dict方法,这比7GB有所下降

当我序列化树(使用最高协议)时,生成的文件要小上百倍

当我重新加载pickle文件时,它再次消耗3GB内存。这额外的开销是从哪里来的,是不是与python处理类实例的内存引用有关

更新

感谢拉斯曼斯和古尔奇的解释和建议。我使用树作为文本语料库上信息检索接口的一部分

我最初将子项(最多30个)存储为Numpy数组,然后尝试硬件版本(
ctypes.py_object*30
)、Python数组(
ArrayType
)以及字典和集合类型

列表似乎做得更好(使用guppy来分析内存,以及
\uuuuu slots\uuuu['variable',…]
),但如果可以的话,我仍在尝试将其压缩一点。我对数组的唯一问题是必须提前指定它们的大小,这会导致只有一个子节点的节点有点冗余,而且我有很多这样的节点。;-)

在树被构造之后,我打算通过第二次传递将其转换为概率树,但可能我可以在树被构造时这样做。在我的例子中,由于构建时间不太重要,所以array.array()听起来很有用,值得一试,谢谢你的提示,非常感谢


我会让你知道它是怎么回事。

如果你试图修改一个空列表,你会得到:

>>> s = StringIO()
>>> pickle.dump([], s)
>>> s.getvalue()
'(l.'
同样地,
(d.
表示一个空的
dict
。这是三个字节

  • 参考计数
  • 一个类型ID,依次包含指向类型名称的指针和用于内存分配的簿记信息
  • 指向指向实际元素的指针向量的指针
  • 还有更多的簿记信息
在我的机器上,它有64位指针,Python列表头对象的
sizeof
是40个字节,因此这是一个数量级。我假设一个空的
dict
将具有类似的大小

然后,
list
dict
都使用过度分配策略来获取其主要操作,
malloc
引入了开销、对齐、您可能知道或可能不知道的成员属性以及各种其他因素,这些因素使您获得了第二个数量级


总结:pickle是Python对象的一种非常好的压缩算法:)

您是否只构建一次树,然后使用它而不进一步修改它?在这种情况下,您可能需要考虑使用动态结构和静态使用的单独结构。

dict和object非常适合动态修改,但在只读场景中它们的空间效率不高。我不知道您使用后缀树的确切目的是什么,但是您可以让每个节点由一个排序的array.array('c')的2元组和一个等长的子节点元组(一个元组,而不是一个向量,以避免过度分配)表示。使用对分模块遍历树以在数组中查找。数组中字符的索引将对应于子节点元组中的子节点。这样可以避免使用dict、object和vector


您可以在构造过程中执行类似的操作,可能使用子节点向量而不是子节点元组。但这当然会降低构造速度,因为在排序向量中插入新节点是O(N)。

动态结构和静态结构之间的差异也是磁盘上的数据小得多的原因。它存储为一个紧凑的静态结构。想象一下,每次在这个块中间添加一个节点会有多慢。我对泡菜印象深刻,甚至还有可能使用CkutoOLS优化函数将文件大小减少25%。泡菜非常有效。:-)