内存效率:一个大字典或较小字典的字典?

时间:2009-03-22 18:27:49

标签: python memory dictionary performance

我正在用Python(2.6)编写一个应用程序,它要求我使用字典作为数据存储。

我很好奇是否有更大的内存效率来拥有一个大字典,或者将其分解为许多(更多)更小的字典,然后有一个“索引”字典,其中包含对所有较小字典的引用字典。

我知道列表和字典通常会有很多开销。我读到某处python内部分配了足够的空间,字典/列表项目的权力为2。

我对python有足够的新意,我不确定是否还有其他意想不到的内部复杂性/类似的事情,这对普通用户来说并不明显,我应该考虑。

其中一个困难是知道2系统的功能如何计算“项目”?是每个键:对计为1项?这似乎很重要,因为如果你有一个100项单片词典,那么将分配空间100 ^ 2项。如果你有100个单项词典(1键:对),那么每个词典只会被分配1 ^ 2(也就是没有额外的分配)?

任何明确列出的信息都会非常有用!

7 个答案:

答案 0 :(得分:73)

三点建议:

  1. 使用一个字典。
    它更容易,更直接,而其他人已经为您优化了这个问题。在你实际测量代码并追踪性能问题之前,你没有理由不做简单,直截了当的事情。

  2. 稍后进行优化。
    如果你真的担心性能,那么抽象问题就让一个类包装你最终使用的查找机制并编写代码来使用这个类。如果您发现需要其他数据结构以获得更高的性能,可以稍后更改实现。

  3. 阅读哈希表。
    字典是hash tables,如果您担心它们的时间或空间开销,您应该阅读它们的实现方式。这是基础计算机科学。缺点是哈希表是:

    • 平均情况 O(1)查询时间
    • O(n)空间(预计 2n ,具体取决于各种参数)

    我不知道你在哪里读到它们是 O(n ^ 2)空间,但是如果它们是,那么它们将不会广泛实用,因为它们在今天的大多数语言中都是如此。哈希表的这些不错的属性有两个优点:

    1. O(1)查询时间意味着您不会为查找时间支付更大字典的费用,因为查找时间不依赖于大小。
    2. O(n)空间意味着你不会因为将字典分成小块而获得太多收益。空间与元素的数量呈线性关系,因此许多小字典不会占用比一个大字体少得多的空间,反之亦然。如果他们是 O(n ^ 2)空间,那就不是真的,但幸运的是,他们不是。
    3. 以下是一些可能有用的资源:

      • Wikipedia article on Hash Tables列出了哈希表中使用的各种查找和分配方案。
      • GNU Scheme documentation讨论了哈希表可以占用多少空间,包括正式讨论为什么“哈希表使用的空间量与数量成正比表“中的关联。这可能会让你感兴趣。

      如果您发现实际需要优化字典实现,可以考虑以下事项:

      • 以下是Python词典的C源代码,以防您需要所有详细信息。这里有大量的文档:
      • 以下是python implementation,如果您不喜欢阅读C.
        (感谢Ben Peterson
      • Java Hashtable class docs讨论了加载因子的工作原理,以及它们如何影响哈希占用的空间。请注意,您的加载因子与 rehash 所需的频率之间需要权衡。重做可能会很昂贵。

答案 1 :(得分:17)

如果你正在使用Python,那么你真的不应该首先担心这类事情。只需以最适合 需求的方式构建数据结构,而不是计算机。

这有点过早优化,而不是性能提升。如果某些东西确实存在瓶颈,那么就会对你的代码进行分析,但在那之前,让Python做它所做的事情并专注于实际的编程任务,而不是基础的机制。

答案 2 :(得分:8)

“简单”通常比“聪明”更好,特别是如果你没有经过考验的理由超越“简单”。无论如何,“内存高效”是一个模糊的术语,当你考虑持久化,序列化,缓存,交换以及其他人已经考虑过的一大堆其他内容时会有权衡,所以在大多数情况下你不会需要。

认为“正确处理它的最简单方法”稍后进行优化。

答案 3 :(得分:7)

过早优化bla bla,不要做bla bla。

我认为你误解了两个额外分配的 power 。我认为它只是两个乘数。 x * 2,而不是x ^ 2.

我在各种python邮件列表上看过几次这个问题。

关于记忆,这是一个这样的讨论的解释版本(该帖子想要存储数亿个整数):

  1. 如果您只想测试成员身份,则set()比dict()更节省空间
  2. gmpy有一个bitvector类型类,用于存储密集的整数集
  3. Dicts保持在50%到30%之间,并且条目大约是12个字节(尽管真实数量会因平台而有所不同)。
  4. 所以,你拥有的对象越少,你将要使用的内存越少,你要做的查找就越少(因为你必须在索引中查找,然后在第二次查找实际价值)。

    像其他人一样说,看看你的瓶颈。保持成员资格set()和值dict()可能会更快,但你将使用更多的内存。

    我还建议将其重新发布到特定于python的列表中,例如comp.lang.python,它比我自己的知识渊博的人更多,他们会为你提供各种有用的信息。

答案 4 :(得分:5)

如果您的字典太大而不适合内存,您可能需要查看ZODB,这是一个非常成熟的Python对象数据库。

db的'root'与字典具有相同的接口,您不需要一次将整个数据结构加载到内存中,例如您可以通过提供开始和结束键来迭代结构的一部分。

它还提供交易和版本控制。

答案 5 :(得分:2)

老实说,无论是在性能还是在内存使用方面,你都无法区分它们。除非您处理数以千万计或更多的项目,否则性能或内存影响只是噪音。

从你措辞第二句的方式来看,听起来像是一首大词典是你的第一句倾向,并且与你想要解决的问题更紧密地匹配。如果这是真的,那就去吧。你会发现Python的每个人都认为“正确”的解决方案几乎总是那些尽可能简单明了的解决方案。

答案 6 :(得分:1)

通常,字典词典除了表现原因外,还有用。即,它们允许您存储有关数据的上下文信息,而无需在对象本身上添加额外字段,并且可以更快地查询数据子集。

就内存使用而言,一个大型词典使用的ram少于多个较小的词典。请记住,如果您正在嵌套字典,那么每个额外的嵌套层将使您需要分配的字典数量大致翻倍。

就查询速度而言,由于所需的查找次数增加,多个dicts将花费更长的时间。

所以我认为回答这个问题的唯一方法就是让你分析自己的代码。但是,我的建议是使用使您的代码最干净,最容易维护的方法。在Python的所有功能中,字典可能是最佳调整以获得最佳性能。