up,
StringBuilder sb=new StringBuilder();
sb.Append(str1);
sb.Append(str2);
sb.Append(str3);
...
据说速度比str1+str2+str3快100倍!
StringBuilder sb=new StringBuilder();
sb.Append(str1);
sb.Append(str2);
sb.Append(str3);
...
据说速度比str1+str2+str3快100倍!
解决方案 »
- IHTMLDocument2 使用 write 方法后, 内存不释放
- datagridview 隐藏行
- 跪求:异步发送邮件报错"发送邮件失败。"
- 求一个c#正则表达式的写法
- JS下,如何让层从屏的右下角弹出?
- 请教:如何在客户端获得imagebutton的X,Y坐标?
- 关于System.Diagnostics.Process.Start
- 那里有好的C#代码,下载啊(比较系统性的)?
- 请问各位,有没有办法用编程的方法生成一个强类型的数据集?
- 关于精度的问题,请高手进来解决,大家可以学习一下
- 菜单与权限的问题!!!分不够可另开贴再加!!
- 兄弟们,怎么把一个打印机的默认页面设置成你想要的,比如A4??
StringBuilder是快,但只有极少应用是才是100倍或以上。static public string String::Contact(...)是最快的。
string是引用类型,在多个字符串加时,程序要为每一个string的实例分配空间,而stringbuillder是值类型,内存在堆栈分配,而且不像string一样有多个实例,它是微软专门用来对付字符串相加的。下面这种方法在大规模的应用
是的性能表现明显比不上stringbuillder---
string a=str1+str2+str3+str4;你可以在MSDN中查找一下,看看有没有
string a=str1
a+=str3;
a+=str2;....
单纯连接4个字符串。
string a=str1+str2+str3+str4;最快使用
StringBuilder
和
string a=str1;
a+=str2;
a+=str3;
a+=str4;到底是谁我还不清楚。String::Contact的一个重载的代码如下:
public static string Concat(string str0, string str1, string str2, string str3) {
int local0;
string local1; if (str0 == null && str1 == null)
if (str2 == null && str3 == null)
return String.Empty;
if (str0 == null)
str0 = String.Empty;
if (str1 == null)
str1 = String.Empty;
if (str2 == null)
str2 = String.Empty;
if (str3 == null)
str3 = String.Empty;
local0 = str0.Length + str1.Length + str2.Length + str3.Length;
local1 = String.FastAllocateString(local0);
String.FillStringChecked(local1, 0, str0);
String.FillStringChecked(local1, str0.Length, str1);
String.FillStringChecked(local1, str0.Length + str1.Length, str2);
String.FillStringChecked(local1, str0.Length + str1.Length + str2.Length, str3);
return local1;
}
string a=str1;
a+=str2;
a+=str3;
a+=str4;
是一样的,都要生成同样多的string实例,即内存分配是一样的.在微软的MSDN里是找不出这样的代码的。为什么有了一个string,还要做一个stringbuilder,你想一想吧,上面已经说得很清楚拉。另外,在今年获奖的.NET测试工具中,排在首位的Compuware Devpartner里有一个代码规则检查器,就对这种代码明令禁止,
意思就是,在代码的性能问题上,"不因善小而不为,勿以恶小而为之。"
说得严重一点,那是垃圾代码。
你没有试过xxx=xxx+"111"+xxx2+"222"+xxx3+"xxx3"..等情况?
你都是用StringBuilder的?你都不写垃圾代码的?那如果你认为
string a=str1+str2+str3+str4和
string a=str1;
a+=str2;
a+=str3;
a+=str4;
是一样的,
那么请你解释一下,,
为什么string str="it's "+new Object();
能够编译通过?
using System;namespace abc
{
public class a
{
static void Main()
{
string s="1"+"2"+"3";
Console.WriteLine(s);
}
}
}
它的IL代码是:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 13 (0xd)
.maxstack 1
.locals init (string V_0)
IL_0000: ldstr "123"
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: call void [mscorlib]System.Console::WriteLine(string)
IL_000c: ret
} // end of method a::Main 在这里我们看到这么一句: ldstr "123",String 是引用类型,可它却没有newobj指令,这说明CLR构造String与其他的对象不一样。还有,不用我说你们都看到了:为什么是“123”,原因是编译器在编译时将它们合并成一个字符串放到了程序集的元数据中(仅限于文字字符)。这样,运行时CLR直接将它们取出来用就OK了,不用再“分别取出来,重新分配内存,复制数据“。关于这个问题:
string a=str1+str2+str3+str4和
string a=str1;
a+=str2;
a+=str3;
a+=str4;
是一样的,我的认为是:它们是不一样的,
请看这个例子:
using System;namespace abc
{
public class a
{
static void Main()
{
string s1="1";
string s2="2";
string s3="3";
string s=s1+s2+s3;
Console.WriteLine(s);
}
}
}
它的IL代码是:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 34 (0x22)
.maxstack 3
.locals init (string V_0,
string V_1,
string V_2,
string V_3)
IL_0000: ldstr "1"
IL_0005: stloc.0
IL_0006: ldstr "2"
IL_000b: stloc.1
IL_000c: ldstr "3"
IL_0011: stloc.2
IL_0012: ldloc.0
IL_0013: ldloc.1
IL_0014: ldloc.2
IL_0015: call string [mscorlib]System.String::Concat(string,
string,
string)
IL_001a: stloc.3
IL_001b: ldloc.3
IL_001c: call void [mscorlib]System.Console::WriteLine(string)
IL_0021: ret
} // end of method a::Main这里我们关心的是这一句:System.String::Concat(string, string,string)
这一句的源代码上面给出来了,它实现分配一块内存,然后将s1,s2,s3的内容复制过去。
再请看:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 55 (0x37)
.maxstack 2
.locals init (string V_0,
string V_1,
string V_2,
string V_3)
IL_0000: ldstr "1"
IL_0005: stloc.0
IL_0006: ldstr "2"
IL_000b: stloc.1
IL_000c: ldstr "3"
IL_0011: stloc.2
IL_0012: ldstr ""
IL_0017: stloc.3
IL_0018: ldloc.3
IL_0019: ldloc.0
IL_001a: call string [mscorlib]System.String::Concat(string,
string)
IL_001f: stloc.3
IL_0020: ldloc.3
IL_0021: ldloc.1
IL_0022: call string [mscorlib]System.String::Concat(string,
string)
IL_0027: stloc.3
IL_0028: ldloc.3
IL_0029: ldloc.2
IL_002a: call string [mscorlib]System.String::Concat(string,
string)
IL_002f: stloc.3
IL_0030: ldloc.3
IL_0031: call void [mscorlib]System.Console::WriteLine(string)
IL_0036: ret
} // end of method a::Mainstring a=str1+str2+str3+str4只分配一次内存,而后者的代码需要分配三次内存。
关于为什么string str="it's "+new Object();能够编译通过?正是因为编译器会为它调用了String的Concat静态方法关于优化的说法,我个人认为主要是针对第一个例子。而编译器为string + 其他类型 调用Concat方法的好处在于string + 值类型 这样的情况:
string s="a";
int n=1;
string s1=s+1;
这时,值类型不用装箱了。
using System;
namespace abc
{
public class a
{
static void Main()
{
DateTime t1=DateTime.Now;
string[] s=new string[50000];
for (int i=0;i<50000;i++)
{
s[i]="a";
}
String.Concat(s);
DateTime t2=DateTime.Now;
Console.WriteLine(t2-t1);
}
}
}
运行结果:00:00:00.0100144
using System;
namespace abc
{
public class a
{
static void Main()
{
DateTime t1=DateTime.Now;
string[] s=new string[50000];
for (int i=0;i<50000;i++)
{
s[i]="a";
}
String.Concat(s);
DateTime t2=DateTime.Now;
Console.WriteLine(t2-t1);
}
}
}
运行结果:00:00:27.8099888
相差确实很大!
using System;
using System.Text;
namespace abc
{
public class a
{
static void Main()
{
DateTime t1=DateTime.Now;
StringBuilder s=new StringBuilder();
for (int i=0;i<50000;i++)
{
s.Append("a");
}
DateTime t2=DateTime.Now;
Console.WriteLine(t2-t1);
}
}
}
运行结果:00:00:00.0100144
using System;namespace abc
{
public class a
{
static void Main()
{
string s1="1";
string s2="2";
string s3="3";
string s4="3";
string s5="3";
string s6="3";
string s7="3";
string s=s1+s2+s3+s4+s5+s6+s7;
Console.WriteLine(s);
}
}
}
上面代码的IL如下:
.method private hidebysig static void Main() cil managed
{
.entrypoint
// Code size 108 (0x6c)
.maxstack 3
.locals init (string V_0,
string V_1,
string V_2,
string V_3,
string V_4,
string V_5,
string V_6,
string V_7,
string[] V_8)
IL_0000: ldstr "1"
IL_0005: stloc.0
IL_0006: ldstr "2"
IL_000b: stloc.1
IL_000c: ldstr "3"
IL_0011: stloc.2
IL_0012: ldstr "3"
IL_0017: stloc.3
IL_0018: ldstr "3"
IL_001d: stloc.s V_4
IL_001f: ldstr "3"
IL_0024: stloc.s V_5
IL_0026: ldstr "3"
IL_002b: stloc.s V_6
IL_002d: ldc.i4.7
IL_002e: newarr [mscorlib]System.String
IL_0033: stloc.s V_8
IL_0035: ldloc.s V_8
IL_0037: ldc.i4.0
IL_0038: ldloc.0
IL_0039: stelem.ref
IL_003a: ldloc.s V_8
IL_003c: ldc.i4.1
IL_003d: ldloc.1
IL_003e: stelem.ref
IL_003f: ldloc.s V_8
IL_0041: ldc.i4.2
IL_0042: ldloc.2
IL_0043: stelem.ref
IL_0044: ldloc.s V_8
IL_0046: ldc.i4.3
IL_0047: ldloc.3
IL_0048: stelem.ref
IL_0049: ldloc.s V_8
IL_004b: ldc.i4.4
IL_004c: ldloc.s V_4
IL_004e: stelem.ref
IL_004f: ldloc.s V_8
IL_0051: ldc.i4.5
IL_0052: ldloc.s V_5
IL_0054: stelem.ref
IL_0055: ldloc.s V_8
IL_0057: ldc.i4.6
IL_0058: ldloc.s V_6
IL_005a: stelem.ref
IL_005b: ldloc.s V_8
IL_005d: call string [mscorlib]System.String::Concat(string[])
IL_0062: stloc.s V_7
IL_0064: ldloc.s V_7
IL_0066: call void [mscorlib]System.Console::WriteLine(string)
IL_006b: ret
} // end of method a::Main代码好像很多,其实意思很简单
统计应该是这样做的:
当然可以指定StringBuilder的capacity,这样可以快1/5左右。using System;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;namespace L
{
public class L
{
static void Test0()
{
DateTime dt1=DateTime.Now;
for(int count=0;count<666666;count++)
{
string str1="a";
string str2="b";
string str3="c";
string str4="d";
string res=str1+str2+str3+str4;
}
DateTime dt2=DateTime.Now;
Console.WriteLine( (dt2-dt1).TotalMilliseconds ); }
static void Test1()
{
DateTime dt1=DateTime.Now;
for(int count=0;count<666666;count++)
{
string[] strs=new string[4];
for(int i=0;i<4;i++)
{
strs[i]="a";
}
string res=String.Concat(strs);
}
DateTime dt2=DateTime.Now;
Console.WriteLine( (dt2-dt1).TotalMilliseconds );
}
static void Test2()
{
DateTime dt1=DateTime.Now;
for(int count=0;count<666666;count++)
{
StringBuilder sb=new StringBuilder();
for(int i=0;i<4;i++)
{
sb.Append("a");
}
string res=sb.ToString();
}
DateTime dt2=DateTime.Now;
Console.WriteLine( (dt2-dt1).TotalMilliseconds );
}
static void Main()
{
Test0();
Console.WriteLine();
Test1();
Console.WriteLine();
Test2();
}
}
}
楼主的例子确实没问题--------------------
"例如:
string a=str1+str2+str3+str4;
将会变成:
string a=String.Concat(str1,str2,str3,str4);
来编译~~~" -----------------------可能大家误认为str1~4不是常量字符串"111","222",....而是string str1="1111"......
string str4+=..诸如此类,这样的话就会是垃圾了。dy_2000_abc(芝麻开门)代码已经说明了问题,看来我有一点说错了。说到垃圾代码,刚学C#时我经常写那种代码。我想这是每个程序员的成长过程中肯定会经历的,不管他是用C/C++/C#/Delphi,还是Java/VB/ASM等等。关键在于能不断的研究和实践,这一点很佩服dy_2000_abc(芝麻开门)兄,向你学习!;-)
所以我一般也是用StringBuilder我睡了。
>> string a=str1+str2+str3+str4
>> 和
>> string a=str1;
>> a+=str2;
>> a+=str3;
>> a+=str4;
这两个不一样,不光是因为Concat函数调用的次数,而且是临时对象的产生:头一个除了str1234以外没有生成多余的临时对象,而后一个每走一步就丢下一个临时对象交给GC收拾(string是immutable的,a+=b相当于string temp = a + b; a = temp;原先的a就没用了)内存的footprint很不光彩。>> 关于优化的说法,我个人认为主要是针对第一个例子。而编译器为string >> 其他类型 调用Concat方法的好处在于string + 值类型 这样的情况:
>> string s="a";
>> int n=1;
>> string s1=s+1;
>> 这时,值类型不用装箱了。
应该还是要装箱的,Concat有两种形式,一是接受string,一是object;C#编译器不能随便把int32转成string,只能当object,所以要装箱。如果要优化,用string s1=s+1.ToString()要好一点——这个不用装箱。
>> string s="a";
>> int n=1;
>> string s1=s+1;
>> 这时,值类型不用装箱了。
应该还是要装箱的,Concat有两种形式,一是接受string,一是object;C#编译器不能随便把int32转成string,只能当object,所以要装箱。如果要优化,用string s1=s+1.ToString()要好一点——这个不用装箱。"string s="a";
int n=1;
string s1=s+1;其实这里有一个隐含的装箱的过程。大家要注意一下,-------------------------
每个值类型都有一个对应的隐含的引用类型,他是在值类型转换为引用类型时自动创建。不是通常的装箱。看下面的代码:
using System;namespace box1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
string s1="1";
string s2="2";
string s3="3";
string s=s1+s2+s3;
string d=s+1;//这里有一个隐含的装箱 Console.WriteLine(s);
Console.WriteLine(d);
}
}
}.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 )
// Code size 55 (0x37)
.maxstack 3
.locals init ([0] string s1,
[1] string s2,
[2] string s3,
[3] string s,
[4] string d)
IL_0000: ldstr "1"
IL_0005: stloc.0
IL_0006: ldstr "2"
IL_000b: stloc.1
IL_000c: ldstr "3"
IL_0011: stloc.2
IL_0012: ldloc.0
IL_0013: ldloc.1
IL_0014: ldloc.2
IL_0015: call string [mscorlib]System.String::Concat(string,
string,
string)
IL_001a: stloc.3
IL_001b: ldloc.3
IL_001c: ldc.i4.1
IL_001d: box [mscorlib]System.Int32
IL_0022: call string [mscorlib]System.String::Concat(object,
object)
IL_0027: stloc.s d
IL_0029: ldloc.3
IL_002a: call void [mscorlib]System.Console::WriteLine(string)
IL_002f: ldloc.s d
IL_0031: call void [mscorlib]System.Console::WriteLine(string)
IL_0036: ret
} // end of method Class1::Main
隐含的装箱在这里------------------------------
IL_001c: ldc.i4.1
IL_001d: box [mscorlib]System.Int32
IL_0022: call string [mscorlib]System.String::Concat(object,
。
smilefox(笑面狐):
能否告知一下你是在哪里搞到的Compuware Devpartner?
谢谢。
www.compuware-china.comCompuware Numega DevpartnerNumega的东西应该知道吧,softice,boudschecker。。
执行时间61.0279毫秒
看来装箱操作对性能影响较为明显。机器配置:PIII650 256M DELL Latitude笔记本电脑