Python的:减少字典的内存使用情况Python的:减少字典的内存使用情况(Python: Red

2019-05-13 14:57发布

我想了几个文件加载到内存中。 该文件有下列任一3种格式:

  • 串TAB INT
  • 串TAB浮动
  • INT TAB浮动。

事实上,他们是NGRAM静态文件,万一这有助于解决方案。 例如:

i_love TAB 10
love_you TAB 12

目前,我的伪代码现在在做的

loadData(file):
     data = {}
     for line in file:
        first, second = line.split('\t')
        data[first] = int(second) #or float(second)

     return data

要多少出乎我的意料,而文件的磁盘总容量约为21 MB,当加载到内存的过程需要120 - 内存180 MB! (整个蟒应用程序不任何其他数据加载到存储器)。

还有不到10个文件,其中大部分将保持稳定在大约50-80k线,除了目前拥有数百万行的一个文件。

所以,我想问一个技术/数据结构来减少内存消耗:

  • 有什么建议给压缩技术?
  • 如果我还在用快译通,是有什么办法可以减少内存? 是否有可能在Java中设定的“负荷率”作为Python的字典?
  • 如果你有一些其他的数据结构,“M也愿意牺牲一些速度,以减少内存。 然而,这是一个时间敏感的应用程序,这样,一旦用户输入他们的疑问,我觉得这是不太合理的花费超过几秒钟的时间返回结果。 关于这一点,我仍然由谷歌如何能做到谷歌翻译这么快惊讶:他们必须使用大量的技术+大量的服务器的权力吗?

非常感谢你。 我期待着您的咨询。

Answer 1:

我不能提供一个完整的战略,这将有助于改善内存占用,但我相信它可以帮助分析究竟是采取这么多的内存。

如果你看一下Python实现词典的(这是一个相对直观的实现一个哈希表),以及内置的字符串和整数数据类型的实现,例如这里 (特别object.h,intobject .H,stringobject.h和dictobject.h,以及在../Objects相应的* .c文件),你可以用一些准确的预期空间要求计算:

  1. 整数 。一个固定大小的对象,即,它包含一个引用计数,一个类型的指针和实际整数,在总通常为32位系统上的至少12个字节和一个64位的系统上的24个字节 ,不考虑额外的空间可能通过比对丢失。

  2. 一个字符串对象是可变大小的,这意味着它包含

    • 引用计数
    • 类型的指针
    • 大小信息
    • 对于懒惰地计算的散列代码空间
    • 状态的信息(例如用于实习字符串)
    • 的指针动态内容

    在32位上总共至少24个字节或64位上60个字节 ,而不是包括用于字符串本身空间。

  3. 字典本身由多个动叶的,各自含有

    • 当前存储的对象的哈希码(即不是从铲斗的位置可预测由于所使用的冲突解决策略)
    • 一个指针到密钥对象
    • 的指针值对象

    在32位上总共至少12个字节和在64位24个字节

  4. 字典开始时用8个空水桶通过在达到它的容量增加一倍时条目的数量调整大小

我进行的测试用的46461个唯一的字符串(337670个字节级联串大小),每个具有一个整数相关联的列表-相似于您的设置,在32位机器上。 根据上述计算,我期望的最低内存占用

  • 46461 *(24 + 12)字节= 1.6 MB的字符串/整数的组合
  • 337670 = 0.3 MB为字符串内容
  • 65536个* 12个字节= 1.6 MB用于散列桶(调整大小的13倍)之后

总共2.65 MB。 (对于64位系统中的对应的计算产生5.5 MB)。

当运行Python解释器空闲,根据它的足迹ps -工具是4.6 MB。 因此创建的字典后的总预期存储器消耗大约4.6 + 2.65 = 7.25 MB。 真正内存占用(根据ps在我的测试是7.6 MB。 我想额外的约 0.35 MB是由通过Python的内存分配策略开销生成消耗(用于存储器领域等)

当然现在很多人会指出,我使用ps来衡量内存占用是不准确的,我对指针类型和整数的32位和64位系统的大小假设可能是错误的许多具体制度。 理所当然的。

但是,尽管如此, 关键的结论 ,我相信,有这些:

  • Python的字典执行占用内存的一个令人惊讶的少量
  • 但受诸多int和(尤其是) 字符串对象采取的引用计数,预先计算的散列码等的空间,是比你想象的更先
  • 几乎没有办法避免的内存开销 ,只要您使用Python,并希望表示为单个对象的字符串和整数-至少我看不出怎么能作到
  • 这可能是值得寻找(或实现自己)一个Python-C扩展 ,实现了存储键和值作为C-指针(而不是Python对象)的哈希。 我不知道是否存在; 但我相信这是可以做到,可能超过一半的减少内存占用。


Answer 2:

1)SQLite的内存听起来像一个伟大的解决方案,它会让一旦加载这是一种享受,你更轻松地查询数据

sqlite3.connect( ':存储器:')

2)你可能想要一个名为元组 - 我敢肯定,他们比字典更轻,您可以访问使用的点符号(我有一个审美偏好反正)性能。

http://docs.python.org/dev/library/collections

3)你可能想看看的Redis: https://github.com/andymccurdy/redis-py

它是快速,将让你轻松坚持的事情,这意味着你不必加载整个集你想用的时候。

4)线索听起来是个好主意,但增加了一些理论的复杂性对你的工作结束。 您可以使用Redis的实现和存储它,虽然,这将进一步提高你的速度。

但总体而言,命名为元组可能是这里的伎俩。



Answer 3:

在磁盘你刚才字符串,加载到Python解释器时,必须创建一个整体结构,每串并为每个字典,除了字符串本身。

有没有办法来减少由http://stardict.sourceforge.net/Dictionaries.php下载使用的内存,但也有其他的方式来解决这个问题。 如果你愿意牺牲一些速度,内存,你应该考虑存储和从SQLite的文件,而不是在内存中加载一切字典查询字符串。



Answer 4:

听起来像特里( http://en.m.wikipedia.org/wiki/Trie )数据结构可能更适合您的内存效率的愿望。

更新:蟒蛇字典的存储效率已经提升为一个问题,但它是从给定的第三方库的可用性标准库拒绝。 请参阅: http://bugs.python.org/issue9520



Answer 5:

你可以将其替换字典blist.sorteddict对于没有内存开销的log(n)的访问。 这是方便,因为它的行为完全像一本字典,即它实现了所有的方法,所以你只需要改变最初的类型。



Answer 6:

如果你想在Python压缩存储在内存中的数值数据,你最好的解决方案可能是NumPy的。

numpy的( http://numpy.org )分配使用本机C的结构的数据结构。 它的大部分数据结构假设你存储一个数据类型,所以这不是适用于所有情况(您可能需要存储空,等等),但它可以是非常,非常,非常快,大约是一样紧凑你可以问。 科学的很多被用它做(参见:SciPy的)。

当然,还有另一种选择:zlib的 ,如果您有:

  • 充足的CPU周期,和
  • ,将不适合到内存中的大量数据

你可以只申报一个“页面”的数据(但大你想要的)作为数组,在数据读取方面,将其存储在阵列中,压缩它,然后在更多的数据读取,直到你有内存中的所有数据,你想。

然后,遍历网页,解压缩,转换回一个数组,并根据需要做您的操作。 例如:

def arrayToBlob(self, inArray):
    a = array.array('f', inArray)
    return a.tostring()

def blobToArray(self, blob, suppressWarning=False):
    try:
        out = array.array('f', [])
        out.fromstring(blob)
    except Exception, e:
        if not suppressWarning:
            msg = "Exception: blob2array, err: %s, in: %s" % (e, blob)
            self.log.warning(msg)
            raise Exception, msg
    return out

一旦你有数据作为一个blob,你可以通过这个斑点为zlib和压缩数据。 如果你有大量重复值,这个斑点可以大大压缩。

当然,它比保持它的所有未压缩的速度较慢,但​​如果你不能在内存中适合它你的选择是有限的开始。

即使压缩,它可能无法全部装入内存,在这一点上,你可以写出来,压缩网页字符串或泡菜等

祝好运!



文章来源: Python: Reducing memory usage of dictionary