字符串插值的缺点是什么?

3

请考虑:

a = str(123456789)
b = str(123456789)
a is b # False

后一行的结果为False,因为ab不是同一个对象,即使它们可以是(因为字符串是不可变的)。因此,如果我有很多相同的字符串“副本”存在,那么我可能会使用比我需要的更多的内存。这就是为什么intern(Py2)和sys.intern(Py3)存在的原因!

a = intern(str(123456789))
b = intern(str(123456789)) # Call to "intern" technically pointless
a is b # True
intern 从内存角度来看有没有任何缺点?(除了调用函数的微小时间成本之外)。我从文档中理解到(例如https://docs.python.org/2/library/functions.html#intern),只要我保持对字符串的引用,字符串就会一直存在于 intern 表中,因此在只有一个字符串副本的情况下,这应该与直接分配给字符串使用相同的内存量,如果我有多个副本,那么显然当我将其 intern 后,内存使用量会更低。

3
字符串池的目标不是为了节省内存(尽管这是一个好的副作用),而是为了加速字典成员测试 - Martijn Pieters
在假设您使用了太多内存之前,请先检查您的配置文件。您正在做什么使您认为内存中有多个相同字符串的副本? - chepner
@Martijn:仍然是同一个问题。 :) - acdr
@chepner:我这样做了。 这是一个“有时候”的问题,我想确保通过内部解决通用情况中的问题时,不会引入其他问题。 - acdr
1
显式对字符串进行国际化的另一个缺点是有时它们会被Python 天真地国际化,因此intern()调用是无意义的。然而,要想弄清楚这个实现细节发生的时间还是需要一些运气的;请阅读:http://guilload.com/python-string-interning/ - Chris_Rands
2个回答

3

这里有两个不足之处:

  • 使用 sys.intern() 调用的 CPU 成本。调用函数需要将当前帧推入堆栈,当函数返回时再弹出。如果您对大量字符串进行此操作,则成本会增加。这是 CPU 循环与内存之间的权衡,需要考虑。

  • 如果您的字符串大多数情况下仅使用一次,则可能会使用更多内存。因为 interning 还会在哈希表中查找字符串对象,而哈希表必须分配比存储的字符串数量更多的内存插槽。使用具有 N + 开销百分比插槽的哈希表 可能 超过 N 个字符串所需的内存,每个字符串都很少使用,因此不会重复。

话虽如此,我们在多千兆字节的内存缓存中成功地使用了 interning,并取得了显着的效果,因为该缓存中的字符串必须出现在树结构的多个位置。


我认为第一个只需要时间成本(因为堆栈帧再次释放)。当然,在堆栈上推送临时值会增加一点额外的内存,但我认为这并不是非常相关的。 - Willem Van Onsem
@WillemVanOnsem:澄清一下,我那里并不是在谈论内存成本。 - Martijn Pieters

2

当然,内存的减少取决于“重复”的数量。如果没有重复,这实际上只会消耗更多的内存,因为Python还要存储哈希表来进行查找以进行内部化处理(它必须检查字符串是否已经存在)。

此外,字符串内部化有两个好处:(1)更快的相等性检查:您只需比较引用(就像在此处使用is一样);和(2)通常可以减少内存使用,因为您当然会将“有趣”的字符串进行内部化。


这篇文章应该真正融入到问题中,但它却完全不是一个预期的答案... - Right leg
这怎么会是一个完全相反的预期答案呢?原帖问是否存在内存方面的缺点,而回答是:是的,哈希表本身也需要内存...看起来像个答案,不是吗? - Willem Van Onsem
抱歉,我的错。那么你的回答(无意冒犯)格式很差,因为这两个优点实际上掩盖了缺点...我真心建议你修改一下格式。 - Right leg
@Rightleg:交换了段落。更好了吗? - Willem Van Onsem
实际上,我认为最引人注目的是列表,所以我也会交换格式... 呃,可能只是我的口味。无论如何,你的帖子仍然很好。 - Right leg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接