String vs. StringBuilder

Kuv*_*uvo 208 .net c# performance

我理解StringStringBuilder(StringBuilder可变)之间的区别,但两者之间是否有很大的性能差异?

我正在研究的程序有很多案例驱动的字符串附加(500+).使用StringBuilder更好的选择?

Jay*_*uzi 229

是的,性能差异很大.请参阅知识库文章" 如何提高Visual C#中的字符串连接性能 ".

我一直尝试编码以获得清晰度,然后再针对性能进行优化.这比反过来要容易得多!但是,看到两者之间的应用程序存在巨大的性能差异,我现在仔细考虑一下.

幸运的是,在代码上运行性能分析以查看您花费时间的位置,然后将其修改为StringBuilder在需要的地方使用,这是相对简单的.

  • 一个好的经验法则是在你不打算改变它时使用字符串,如果你要改变它就使用StringBuilder. (44认同)
  • 我非常喜欢这个答案,尤其是在表现之前为了清晰而编码的建议.作为开发人员,我们花费尽可能多的时间来阅读代码,就像我们编写代码一样. (31认同)
  • 它仍然取决于人们如何使用它,以供参考实际测试我喜欢[编码恐怖 - 悲剧悲剧的微优化剧场](http://www.codinghorror.com/blog/2009/01/the-sad -tragedy-的微优化-theater.html) (3认同)
  • 根据我的经验,如果您尝试连接 10-15 个左右的字符串,那么您可以使用字符串,但如果没有。的字符串不止于此,然后使用字符串生成器 (2认同)

Jam*_*ran 54

为了澄清Gillian关于4字符串的内容,如果你有这样的话:

string a,b,c,d;
 a = b + c + d;
Run Code Online (Sandbox Code Playgroud)

那么使用字符串和加号运算符会更快.这是因为(就像Eric指出的那样),它在内部自动使用StringBuilder(实际上,它使用StringBuilder也使用的原语)

但是,如果您正在做的更接近:

string a,b,c,d;
 a = a + b;
 a = a + c;
 a = a + d;
Run Code Online (Sandbox Code Playgroud)

然后你需要显式使用StringBuilder..Net不会在这里自动创建StringBuilder,因为它毫无意义.在每一行的末尾,"a"必须是(不可变的)字符串,因此必须在每一行上创建和配置StringBuilder.为了速度,你需要使用相同的StringBuilder,直到你完成构建:

string a,b,c,d;
StringBuilder e = new StringBuilder();
 e.Append(b);
 e.Append(c);
 e.Append(d);
 a = e.ToString();
Run Code Online (Sandbox Code Playgroud)

  • 没有理由为什么C#编译器需要以不同于第一个的方式处理第二个样本.特别是没有义务在每一行的末尾产生一个字符串.编译器可能会按照您的说法运行,但它没有义务这样做. (5认同)

cal*_*ins 28

StringBuilder是优选的,如果您在代码传递中执行多个循环或分叉...但是,对于PURE性能,如果您可以使用SINGLE字符串声明,那么性能更高.

例如:

string myString = "Some stuff" + var1 + " more stuff"
                  + var2 + " other stuff" .... etc... etc...;
Run Code Online (Sandbox Code Playgroud)

比表现更高效

StringBuilder sb = new StringBuilder();
sb.Append("Some Stuff");
sb.Append(var1);
sb.Append(" more stuff");
sb.Append(var2);
sb.Append("other stuff");
// etc.. etc.. etc..
Run Code Online (Sandbox Code Playgroud)

在这种情况下,StringBuild可以被认为是更易于维护的,但是不比单个字符串声明更高效.

10次​​中有9次...使用字符串生成器.

一方面注意:string + var也比内部使用StringBuilder的string.Format方法(通常)更高效(当有疑问时......检查反射器!)

  • 我希望你能说你怎么知道/如何验证. (16认同)
  • 考虑使用String.Format()来连接少量的小字符串,尤其是目标是格式化消息以显示用户. (3认同)
  • 此答案中的信息不正确.StringBuilder比在同一语句中完成的连接快一点; 但是,如果你做了数十万次,你只会注意到两者之间的差异([来源](http://blog.codinghorror.com/the-sad-tragedy-of-micro-optimization-theater/) ).正如消息来源所说,"这没关系!" (3认同)
  • 您无法验证反射器的性能:通过定时释放代码验证性能,使用分析器进行分析并使用反射器寻求解释. (2认同)

小智 23

此基准测试表明,当组合3个或更少的字符串时,常规连接更快.

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder可以显着提高内存使用率,尤其是在将500个字符串组合在一起的情况下.

请考虑以下示例:

string buffer = "The numbers are: ";
for( int i = 0; i < 5; i++)
{
    buffer += i.ToString();
}
return buffer;
Run Code Online (Sandbox Code Playgroud)

记忆中会发生什么?创建以下字符串:

1 - "The numbers are: "
2 - "0"
3 - "The numbers are: 0"
4 - "1"
5 - "The numbers are: 01"
6 - "2"
7 - "The numbers are: 012"
8 - "3"
9 - "The numbers are: 0123"
10 - "4"
11 - "The numbers are: 01234"
12 - "5"
13 - "The numbers are: 012345"
Run Code Online (Sandbox Code Playgroud)

通过将这五个数字添加到字符串的末尾,我们创建了13个字符串对象!其中12个没用!哇!

StringBuilder修复了这个问题.它不是我们经常听到的"可变字符串"(.NET中的所有字符串都是不可变的).它的工作原理是保留一个内部缓冲区,一个char数组.调用Append()或AppendLine()将字符串添加到char数组末尾的空白处; 如果数组太小,它会创建一个新的更大的数组,并在那里复制缓冲区.因此,在上面的示例中,StringBuilder可能只需要一个数组来包含字符串的所有5个添加项 - 具体取决于其缓冲区的大小.你可以告诉StringBuilder它的缓冲区在构造函数中应该有多大.

  • 小问题:说“我们创建了 13 个字符串对象,其中 12 个没用”,然后说 StringBuilder 解决了这个问题,这有点奇怪。毕竟,*六个*你别无选择,只能创建;它们来自`i.ToString()`。所以使用StringBuilder,你还是要创建6+1个字符串;它将创建 13 个字符串减少到创建 7 个字符串。但这仍然是错误的看待方式。六个数字字符串的创建无关紧要。底线:你根本不应该提到`i.ToString()`创建的六个字符串;它们不是效率比较的一部分。 (2认同)

Dii*_*zzy 22

一个简单的例子来演示使用String串联时的速度差异StringBuilder:

System.Diagnostics.Stopwatch time = new Stopwatch();
string test = string.Empty;
time.Start();
for (int i = 0; i < 100000; i++)
{
    test += i;
}
time.Stop();
System.Console.WriteLine("Using String concatenation: " + time.ElapsedMilliseconds + " milliseconds");
Run Code Online (Sandbox Code Playgroud)

结果:

使用字符串连接:15423毫秒

StringBuilder test1 = new StringBuilder();
time.Reset();
time.Start();
for (int i = 0; i < 100000; i++)
{
    test1.Append(i);
}
time.Stop();
System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds");
Run Code Online (Sandbox Code Playgroud)

结果:

使用StringBuilder:10毫秒

结果,第一次迭代花费了15423 ms,而第二次迭代StringBuilder花费了10 ms.

在我看来,使用StringBuilder速度更快,速度更快.


Sha*_*r K 12

是的,StringBuilder在对字符串执行重复操作时提供更好的性能.这是因为所有更改都是针对单个实例进行的,因此可以节省大量时间,而不是创建新的实例String.

String Vs Stringbuilder

  • String

    1. System命名空间
    2. 不可变(只读)实例
    3. 当连续发生值变化时,性能会下降
    4. 线程安全
  • StringBuilder (可变字符串)

    1. System.Text命名空间
    2. 可变实例
    3. 显示更好的性能,因为对现有实例进行了新的更改

强烈推荐dotnet mob文章:C#中的String Vs StringBuilder.

相关的Stack Overflow问题:字符串在C#中没有变化时字符串的可变性?.


Reh*_*hah 10

字符串与字符串生成器:

首先,您必须知道这两个类在哪个组件中生活?

所以,

字符串存在于System名称空间中。

StringBuilder存在于System.Text名称空间中。

对于字符串声明:

您必须包括System名称空间。这样的事情。 Using System;

对于StringBuilder声明:

您必须包括System.text名称空间。这样的事情。 Using System.text;

现在来实际的问题。

stringStringBuilder之间的区别是什么?

两者之间的主要区别在于:

字符串是不可变的。

StringBuilder是可变的。

所以现在让我们讨论不可变可变之间的区别

可变的::表示可变的。

不可变::表示不可更改。

例如:

using System;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // String Example

            string name = "Rehan";
            name = name + "Shah";
            name = name + "RS";
            name = name + "---";
            name = name + "I love to write programs.";

            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah RS --- I love to write programs."
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,我们将更改同一对象5次。

因此,显而易见的问题是!当我们将相同的琴弦改变5次时,实际上发生了什么。

这是我们将相同的字符串更改5次后发生的情况。

让我们看看图。

在此处输入图片说明

说明:

当我们第一次将此变量“ name”初始化为“ Rehan”时,即string name = "Rehan" 在堆栈“ name”上创建此变量并指向该“ Rehan”值。执行此行后:“ name = name +” Shah“。引用变量不再指向该对象” Rehan“,现在指向” Shah“,依此类推。

string是不可变的,这意味着一旦我们在内存中创建了对象,就无法更改它们。

因此,当我们隐含name变量时,先前的对象保留在内存中,并创建了另一个新的字符串对象...

因此,根据上图,我们有五个对象,四个对象被扔掉了,根本没有使用。它们仍然保留在内存中,并且占用内存量。“垃圾收集器”对此负责,因此请清除内存中的资源。

因此,在任何情况下,当我们一遍又一遍地操作字符串时,都会有许多对象创建并保留在内存中。

这就是字符串Variable的故事。

现在,让我们看一下StringBuilder对象。 例如:

using System;
using System.Text;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // StringBuilder Example

            StringBuilder name = new StringBuilder();
            name.Append("Rehan");
            name.Append("Shah");
            name.Append("RS");
            name.Append("---");
            name.Append("I love to write programs.");


            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah Rs --- I love to write programs."
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,在这种情况下,我们将更改同一对象5次。

因此,显而易见的问题是!当我们将相同的StringBuilder更改5次时,实际上发生了什么。

这就是我们更改相同的StringBuilder 5次时发生的情况。

让我们看看图。 在此处输入图片说明

说明: 对于StringBuilder对象。您不会得到新对象。同一对象将在内存中发生更改,因此即使您将对象更改了10,000次,我们仍然只有一个stringBuilder对象。

您没有很多垃圾对象或未引用的stringBuilder对象,因为为什么可以更改它。它是可变的,意味着它会随时间变化吗?

差异:

  • 在System命名空间中存在String,而在System.Text命名空间中存在Stringbuilder。
  • 在StringBuilder是mutabe的地方,string是不可变的。


mos*_*ald 8

StringBuilder减少了分配和分配的数量,但代价是使用了额外的内存.如果使用得当,它可以完全消除编译器反复分配越来越大的字符串直到找到结果的需要.

string result = "";
for(int i = 0; i != N; ++i)
{
   result = result + i.ToString();   // allocates a new string, then assigns it to result, which gets repeated N times
}
Run Code Online (Sandbox Code Playgroud)

String result;
StringBuilder sb = new StringBuilder(10000);   // create a buffer of 10k
for(int i = 0; i != N; ++i)
{
   sb.Append(i.ToString());          // fill the buffer, resizing if it overflows the buffer
}

result = sb.ToString();   // assigns once
Run Code Online (Sandbox Code Playgroud)


小智 5

String 或 StringBuilder 对象的串联操作的性能取决于内存分配发生的频率。String 串联操作总是分配内存,而 StringBuilder 串联操作仅在 StringBuilder 对象缓冲区太小而无法容纳新数据时才分配内存。因此,如果连接固定数量的 String 对象,则 String 类更适合用于连接操作。在这种情况下,编译器甚至可能将单个连接操作合并为单个操作。如果连接任意数量的字符串,则 StringBuilder 对象更适合用于连接操作;例如,如果循环连接随机数量的用户输入字符串。

来源:MSDN