2009-12-29 124 views
5

所以...我有这种情况下,我有一个Foreach循环,通过复选框列表来检查哪些被选中。对于每个选定的复选框,我必须进行一个非常长的字符串连接,包含30个平均长度为20个字符的不同字符串,然后将其作为HTTP请求发送出去。 2个字符串取决于所选复选框的索引/值。字符串连接VS字符串生成器追加

根据用户的数据,复选框列表的长度也是可变的。我会说列表的平均长度是20,但可以达到50-60。所以最糟糕的情况是执行整个字符串连接60次左右。

现在我正在通过'+'运算符通过简单字符串连接来完成它,但是我想知道用Stringbuilder做它会更快。当然,这意味着我不得不在循环中创建一个Stringbuilder对象,或者在循环之前创建它,并在发送HTTP请求之后调用Stringbuilder.Remove。

我很感激任何人都可以分享有关此问题的任何见解。

编辑
感谢所有的答复大家,所以从我收集的,最好的办法,我去这样做会是这样的:

+0

我很抱歉,看来我不太了解Stringbuilder。所以调用Stringbuilder.ToString()清除Stringbuilder? – Kronon 2009-12-29 05:06:14

+0

否。将Length属性设置为零会清除它。 – 2009-12-29 05:09:51

+0

someStringBuilder.length = 0; – 2009-12-29 05:11:24

回答

14

使用StringBuilder。这就是它的目的。

字符串是不可变的。字符串连接创建一个新字符串,需要更多的内存,通常被认为是慢:

string a = "John" + " " + "Saunders"; 

这将创建一个字符串“约翰”,然后创建另一个字符串“约翰·桑德斯”,最后,分配,为“一” 。 “约翰”留给垃圾收集。

string a = "John"; 
a += " "; 
a += "Saunders"; 

这是差不多的,因为“约翰”是一个新的字符串“约翰”,这是一个新的字符串“约翰·桑德斯”取代取代。原件留给垃圾收集。

在另一方面,StringBuilder被设计为附加,删除等


例子:

StringBuilder sb = new StringBuilder(); 
for (int i=0; i<n; i++) 
{ 
    sb.Length = 0; 
    sb.Append(field1[i]); 
    sb.Append(field2[i]); 
    ... 
    sb.Append(field30[i]); 
    // Do something with sb.ToString(); 
} 
+0

由于某种原因我喜欢这个答案.. – 2009-12-29 04:57:26

+0

我道歉,如果我的问题似乎轻浮,但我只是想知道如果在每个循环创建一个新的Stringbuilder对象会导致不必要的开销。 – Kronon 2009-12-29 05:01:12

+0

你为什么要创建一个新的? – 2009-12-29 05:02:52

2

一般来说,我会建议使用StringBuilder

您是否测试了这个并检查了性能? 性能是一个问题,您需要多长时间来重写代码

+0

我几乎完成了这个项目,所以现在我只是在寻找各种方法来优化我的代码以获得更好的性能。 – Kronon 2009-12-29 05:03:06

5

这个主题已经多年来分析死亡。最终的结果是,如果您正在进行少量已知数量的连接,请使用'+',否则使用stringbuilder。从你所说的,与'+'连接应该更快。有一个gazillion(给或拿)网站分析这 - 谷歌它。

对于您所说的字符串的大小,无论如何它是微不足道的。

编辑:关于第二个想法,SB可能更快。但就像我说的,谁在乎?

+2

我不同意。如果他正在做30个“+”操作,那么他会分配并丢弃大量的字符串,而不会附加到任何字符串。 – 2009-12-29 05:00:10

+0

你在编辑时已经进入了:)我认为SB可能会更快,但是请记住,所有'丢弃'字符串都由GC处理,它完成了相当高效的工作,而且并不真正处理当前执行路径。 – 2009-12-29 05:03:03

+0

它仍然是不必要的GC工作,可以很容易地避免...它不像我们正在谈论2或3个字符串... – 2009-12-29 05:07:20

2

如果你问这个问题,很可能你应该使用StringBuilder的原因很多,但我会提供两个。

  1. 当你使用字符串连接它分配一个新的缓冲区,并在另一个字符串中的数据复制到新的字符串变量。所以你将会招致许多重复的分配。最后哪个最终会碎片化内存,占用堆空间,并为垃圾收集器做更多工作。另一方面,StringBuilder预先分配一个缓冲区,并且在向其添加字符串时不需要保持重新分配(假设初始缓冲区足够大)。这提高了性能,对内存的征税也少得多。

  2. 作为开发者,我们应该尝试预测未来的增长。假设你的名单随着时间的推移而大幅增长,然后突然开始缓慢地进行。如果你现在可以毫不费力地防止这种情况,那你为什么不这么做?

6

我知道这已经回答了,但我想指出的是,其实,我觉得一直使用的StringBuilder的“盲目地接受福音”的做法是错误的,有时,这是一个情况。

为背景,看到这个博客条目:http://geekswithblogs.net/johnsperfblog/archive/2005/05/27/40777.aspx

这样做的缺点是,对于这种特殊情况下,如描述的那样,你会避免的StringBuilder和利用+操作的正是如此看到更好的性能:

foreach (CheckBox item in FriendCheckboxList) 
{ 
    if (item.Checked) 
    { 
     string request = string1 + 
      string2 + 
      string3 + 
      . 
      . 
      . 
      stringLast; 
     SendRequest(request); 
    } 
} 

原因是C#编译器(从.NET 1.1开始)会将该语句转换为一个单独的IL调用,将String作为参数传递给String.Concat。博客条目做了一个很好的工作,概述了String.Concat的实现细节,但足以说明,这种情况非常有效。

+0

感谢您提出这一点。很多人认为他们在不需要时可以保存GC呼叫。如果它与性能相关,并且它可能很重要,那么测量它!有很少的“总是使用X”规则是正确的。 – 2010-05-10 18:29:29

+1

当有固定数量的字符串连接时,string.Concat比较好。它所需要做的就是添加字符串长度的总和,分配内存,复制每个字符串,然后就完成了。如果你期望做更多的处理,StringBuilder可能会更好。 – Todd 2015-08-15 05:43:24