为什么字符串通常很耗费资源

3

字符串的实现方式是什么导致它们在操作时如此昂贵?

是否无法制作“廉价”的字符串实现?

或者我的理解完全错误?

谢谢


什么让你觉得它们贵?说实话,这完全取决于你对它们的使用方式。 - Draemon
1
昂贵是一个相对的概念。相对于什么而言,操作起来就昂贵呢?字符数组?整数?剪刀? - Falaina
需要引用出处!谁说它们难以操作,与什么相比呢? - Peter Recore
1
@Michael:我已经删除了ASP标签。即使他的个人资料中可能有ASP,但这个问题与ASP无关。 - John Saunders
@John Saunders。谢谢,我甚至不是那么感兴趣C#。字符串慢似乎是一个普遍的“特性”。Novatrust解释字符串是字符数组,这正是我想要的。 - Greg B
显示剩余2条评论
9个回答

23

用哪种语言?

字符串通常是不可变的,这意味着对数据的任何更改都会创建一个新的字符串副本。这可能会对大型字符串产生性能影响。

然而,这是一个重要的特性,因为它允许进行优化,例如内部化。内部化通过指向相同数据的相同字符串来减小文本数据的大小。

如果您关心字符串的性能,请使用StringBuilder(在C#和Java中可用)或其他可处理可变文本数据的构造。

如果您正在处理大量文本数据并需要一个强大的字符串解决方案同时仍然节省空间,请考虑使用绳索


1
维基百科链接已经失效,看起来是SO的正则表达式出了问题。 - Will Bickford
感谢novatrust。我对特定的编程语言并不特别感兴趣。Joel在播客中经常提到字符串,并且它们也被提到过其他地方。你关于字符串实际上是一个数组的解释正是我想要的。再次感谢。 - Greg B

2

由于在Java中每次创建对象时都会创建新的副本,因此建议使用StringBuffer。

语法

StringBuffer strBuff=new StringBuffer();
strBuff.append("StringBuffer");
strBuff.append("is");
strBuff.append("more");
strBuff.append("economical");
strBuff.append("than");
strBuff.append("String");
String string=strBuff.tostring();

4
它会自动在附加的单词之间添加空格吗? :P - liori
八年了,为了更新,请使用 StringBuilder,并且当然要在单词之间加上空格。 - Harish

2
字符串的问题在于它们不是原始类型,而是数组。因此,它们遭受与数组相同的速度和内存问题(也许有一些优化)。现在,“廉价”的实现需要大量的东西:连接、indexOf等。有很多方法可以做到这一点。你可以改进实现,但是有一些限制。因为字符串对计算机来说不是“自然”的,所以它们需要更多的内存,并且操纵起来更慢...总是如此。你永远不会得到一个比任何体面的整数求和算法更快的字符串连接算法。

1
我完全同意。现代字符串不是简单的实体。它们被设计用于方便操作。这种功能是有需求的,但也很昂贵。比较一下.NET字符串(或Python)与老式C语言的“string.h”处理方式(以及内存处理方式)。 - CMB

2
很多观点都是正确的。在某些孤立的情况下,你可以作弊,比如使用64位整数一次比较8个字节的字符串,但是你不能优化大量通用情况的操作。如果你有一个“Pascal风格”的字符串和数字长度字段,就可以短路比较来检查字符串是否相同。其他操作通常需要逐字节处理字符或完全复制它们后再使用。 例如,连接 => 获取字符串1的长度,获取字符串2的长度,分配内存,复制字符串1,复制字符串2。可以使用DMA控制器在一个字符串库中执行此类操作,但对于小字符串而言,设置它的开销会超过好处。 Pete

我在去车库的路上想到了这个问题。通常,CPU供应商优化的操作都是数学运算或特定领域的数学运算。例如,DSP或用于模拟和图形的3D矩阵运算。理论上讲,完全可以使用缓存操作和DMA方案来优化字符串操作,只是还没有足够的行业压力迫使供应商优化字符串操作。 - NoMoreZealots

1

这完全取决于你想用它做什么。大多数情况下,除非是替换直接查找中的单个字符,否则通常需要至少1个新数组分配。在最简单的级别上,字符串是字符数组。因此,你想做的几乎任何事情都涉及迭代、删除或插入新内容到一个数组中。


1

了解可变字符串、不可变字符串和绳索,并考虑如何在低级语言(比如C语言)中实现常见操作。请考虑以下内容:

  1. 连接。
  2. 切片。
  3. 获取索引处的字符。
  4. 更改索引处的字符。
  5. 定位字符的索引。
  6. 遍历字符串。

为这些情况提供算法将让您感觉到何时应该使用每种类型的存储。


0
如果你想要一个在任何情况下都能工作的通用字符串,有时需要在某些情况下牺牲效率。这是快速获取一件事和另一件事之间的经典权衡。因此...你可以使用“标准”字符串来正常工作(但不是最优方式),或者使用在某些情况下非常快速但在其他情况下很麻烦的字符串实现。
有时候你需要不可变性,有时候需要随机访问,有时候需要快速插入/删除...

0

字符串的更改和复制往往涉及内存管理。

由于内存管理往往需要某种全局互斥体,这会影响性能,使您的代码难以在多个核心上扩展。


0

谢谢你的链接JCCyC。Joel在播客中对字符串的抱怨是我提出这个问题的原因。 - Greg B

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