哪种方法占用的内存更少,是冻结集还是元组?

2024-05-23 18:18:33 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个对象需要用0-3个字符串“标记”(在20个可能的集合中);这些值都是唯一的,顺序无关紧要。唯一需要对标记执行的操作是检查是否存在特定的标记(specific_value in self.tags)。在

然而,在内存中同时存在大量这样的对象,以至于它超出了我旧计算机的RAM的极限。所以节省几个字节就可以了。在

由于每个对象上的标记太少,我怀疑查找时间会有多重要。但是:在这里使用元组和冻结集有内存区别吗?有没有其他真正的理由用一个来代替另一个呢?在


Tags: 对象内存字符串in标记self字节顺序
3条回答

元组非常紧凑。集合是基于哈希表的,并且依赖于有“空”槽来减少哈希冲突的可能性。在

对于CPython的最新版本,sys._debugmallocstats()显示了许多潜在的有趣信息。在64位Python 3.7.3下:

>>> from sys import _debugmallocstats as d
>>> tups = [tuple("abc") for i in range(1000000)]

tuple("abc")创建一个由3个1字符字符串组成的元组,('a', 'b', 'c')。我将编辑几乎所有的输出:

^{pr2}$

因为我们创建了一百万个元组,所以使用1004692个块的size类是我们想要的;每个块消耗72个字节。在

切换到冻结集,输出结果显示,每个冻结集消耗224字节,比原来多3倍多:

>>> tups = [frozenset(t) for t in tups]
>>> d()
Small block threshold = 512, in 64 size classes.

class   size   num pools   blocks in use  avail blocks
  -            -         -        
...
   27    224       55561         1000092             6

在这种情况下,你得到的另一个答案恰好给出了相同的结果:

>>> import sys
>>> sys.getsizeof(tuple("abc"))
72
>>> sys.getsizeof(frozenset(tuple("abc")))
224

虽然这通常是正确的,但并非总是如此,因为对象可能需要分配比实际需要更多的字节来满足HW对齐要求。getsizeof()对此一无所知,但_debugmallocstats()显示了Python的小对象分配器实际需要使用的字节数。在

例如

>>> sys.getsizeof("a")
50

在32位的机器上,实际上需要使用52个字节,以提供4字节对齐。在64位机器上,当前需要8字节对齐,因此需要使用56字节。在Python3.8(尚未发布)下,在64位机器上需要16字节对齐,而将需要使用64字节。在

但忽略所有这些,元组所需的内存总是比任何具有相同元素数的集合形式都要少,甚至比具有相同元素数的列表还要少。在

如果你想节省内存,考虑一下

  • 通过将标记所在的数据结构提取到外部(单例)数据结构中,以某种优雅换取一些内存节省
  • 使用“flags”(位图)类型的方法,其中每个标记都映射到32位整数的一位。然后,您只需要从对象(标识)到32位整数(标志)的(单例)dict映射。如果没有标志,则字典中没有条目。在

sys.getsizeof似乎是您想要的stdlib选项。。。但我对你的整个用例感到不安

import sys
t = ("foo", "bar", "baz")
f = frozenset(("foo","bar","baz"))
print(sys.getsizeof(t))
print(sys.getsizeof(f))

https://docs.python.org/3.7/library/sys.html#sys.getsizeof

All built-in objects will return correct results, but this does not have to hold true for third-party extensions as it is implementation specific.

…所以不要对这个解决方案感到舒服

编辑:显然,@TimPeters的答案更正确。。。在

相关问题 更多 >