浅析C#中StringBuilder类的高效及与String的对比

时间:2022-02-13 22:17:10

在c#中,在处理字符串拼接的时候,使用stringbuilder的效率会比硬拼接字符串高很多。到底有多高,如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
static void main( string[] args )
{
 string str1 = string.empty;
 stopwatch sw1 = new stopwatch();
 sw1.start();
 for ( int i = 0; i < 10000; i++ )
 {
 str1 = str1 + i.tostring();
 }
 sw1.stop();
 console.writeline( "拼接字符串所耗费时间为:" + sw1.elapsedmilliseconds + "毫秒" );
 stringbuilder str2 = new stringbuilder( 10000 );
 stopwatch sw2 = new stopwatch();
 sw2.start();
 for ( int i = 0; i < 10000; i++ )
 {
 str2.append( i.tostring() );
 }
 sw2.stop();
 console.writeline( "使用stringbuilder所耗费时间为:" + sw2.elapsedmilliseconds + "毫秒" );
 console.readkey();
}

上面代码执行的效果如下:

浅析C#中StringBuilder类的高效及与String的对比

string类型的特别之处在于我们可以像使用值类型那样使用string类型,而实际上string是引用类型。既然是引用类型,clr就会把string类型保存在托管堆上。当我们使用str1 = str1 + i.tostring();进行拼接,由于string类型的恒定性,不会改变str1在内存中的地址,而是在托管堆上创建了另外一个字符串对象。如此,拼接10000次,就创建了10000个string类型对象,效率难免低下。

而stringbuilder会在内存中开辟一块连续的内存,当增加字符串实际上是针对同一块内存的修改,所以效率更高。

当然,到底使用硬拼接字符串,还是使用stringbuilder,不是绝对的,要看情况。当拼接字符串很少的情况下,当然直接硬拼接字符串就行了。

深入string和stringbuilder的区别
string对象是不可改变的。每次使用system.string类中的方法之一或者是进行运算时(如赋值、拼接等),都要在内存中创建一个新的字符串对象,这就需要为该新对象分配内存空间,而stringbuilder则不会。在需要对字符串执行重复修改操作时,与创建新的 string 对象相关的系统开销可能会非常昂贵。如果要修改字符串而不创建新的对象,则可以使用 system.text.stringbuilder 类。例如,当在一个循环中将许多字符串连接在一起时,使用 stringbuilder 类可以提升性能。

string类型对象的特点:
1.它是引用类型,在堆上分配内存
2.运算时会产生一个新的实例
3.string 对象一旦生成不可改变(immutable)
4.定义相等运算符(== 和 !=)是为了比较 string 对象的值(而不是引用)

大家都知道字符串对象是”不可变的”,
对字符串进行操作的方法实际上返回的是新的字符串对象。
在前面的示例中,将 s1 和 s2 的内容连接起来以构成一个字符串时,包含 "orange" 和 "red" 的两个字符串均保持不变。+= 运算符会创建一个包含组合内容的新字符串。结果是 s1 现在引用一个完全不同的字符串。只包含"orange" 的字符串仍然存在,但连接 s1 后将不再被引用。
大量的字符串相加的时候就会有很多想s1一样的 不在被引用,从而造成资源的极大浪费.
大家注意这点

?
1
2
3
string stringvalue = this.m_stringvalue;
 
internal volatile string m_stringvalue;

写到这里,需要有人见看到了 volatile,也许不明白是什么意思,大概的说下.
volatile关键字实现了线程间数据同步,用volatile修饰后的变量不允许有不同于”主”内存区域的变量拷贝。
换句话说,一个变量经volatile修饰后在所有线程中必须是同步的;任何线程中改变了它的值,所有其他线程立即
获取到了相同的值。理所当然的,volatile修饰的变量存取时比一般变量消耗的资源要多一点,因为线程有它自己的
变量拷贝更为高效。

?
1
this.needsallocation(stringvalue, requiredlength)

 

只有在需要的时候才去重新分配.
就分配空间和线程的使用上来讲,stringbuilder肯定比string要高,但是前提是使用频率比较高的情况下.