C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能
本文通过ANTS Memory Profiler工具探索c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能。
本文涉及程序为.NET Core 2.0控制台应用程序。
一、常量字符串拼接

private static void TestPerformance(Action action, int times) { Stopwatch sw = new Stopwatch(); sw.Start(); for(int i = 0; i < times; i++) { action(); } sw.Stop(); Console.WriteLine(action.Method.Name + ", FullTime: " + sw.ElapsedMilliseconds); }

1.+方法
1.1连续拼接
private static void AddTest() { string s = string.Empty; s = "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8"; }
运行时间:
内存情况:
IL代码:

.method private hidebysig static void AddTest() cil managed { // Code size 7 (0x7) .maxstack 8 IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: pop IL_0006: ret } // end of method Program::AddTest

1.2分段拼接

private static void AddWithParamTest2() { string s = string.Empty; s += "1"; s += "2"; s += "3"; s += "4"; s += "5"; s += "6"; s += "7"; s += "8"; }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void AddWithParamTest2() cil managed { // Code size 87 (0x57) .maxstack 2 IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: ldstr "1" IL_000a: call string [System.Runtime]System.String::Concat(string, string) IL_000f: ldstr "2" IL_0014: call string [System.Runtime]System.String::Concat(string, string) IL_0019: ldstr "3" IL_001e: call string [System.Runtime]System.String::Concat(string, string) IL_0023: ldstr "4" IL_0028: call string [System.Runtime]System.String::Concat(string, string) IL_002d: ldstr "5" IL_0032: call string [System.Runtime]System.String::Concat(string, string) IL_0037: ldstr "6" IL_003c: call string [System.Runtime]System.String::Concat(string, string) IL_0041: ldstr "7" IL_0046: call string [System.Runtime]System.String::Concat(string, string) IL_004b: ldstr "8" IL_0050: call string [System.Runtime]System.String::Concat(string, string) IL_0055: pop IL_0056: ret } // end of method Program::AddWithParamTest2

通过IL代码可以看出,分段的+=代码调用的是Concat方法,并且比连续的+多开辟了许多内存空间。
2.Concat方法
2.1分次Concat

private static void ConcatTest() { string s = string.Empty; s = string.Concat(s, "1"); s = string.Concat(s, "2"); s = string.Concat(s, "3"); s = string.Concat(s, "4"); s = string.Concat(s, "5"); s = string.Concat(s, "6"); s = string.Concat(s, "7"); s = string.Concat(s, "8"); }

IL代码:

.method private hidebysig static void AddWithParamTest2() cil managed { // Code size 87 (0x57) .maxstack 2 IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: ldstr "1" IL_000a: call string [System.Runtime]System.String::Concat(string, string) IL_000f: ldstr "2" IL_0014: call string [System.Runtime]System.String::Concat(string, string) IL_0019: ldstr "3" IL_001e: call string [System.Runtime]System.String::Concat(string, string) IL_0023: ldstr "4" IL_0028: call string [System.Runtime]System.String::Concat(string, string) IL_002d: ldstr "5" IL_0032: call string [System.Runtime]System.String::Concat(string, string) IL_0037: ldstr "6" IL_003c: call string [System.Runtime]System.String::Concat(string, string) IL_0041: ldstr "7" IL_0046: call string [System.Runtime]System.String::Concat(string, string) IL_004b: ldstr "8" IL_0050: call string [System.Runtime]System.String::Concat(string, string) IL_0055: pop IL_0056: ret } // end of method Program::AddWithParamTest2

可见IL代码与+分段拼接常量字符串相同,性能相似。
2.2Concat一次拼接常量字符串
private static void ConcatTest2() { string s = string.Empty; string.Concat(s, "1", "2", "3", "4", "5", "6", "7", "8"); }
运行时间:
内存情况:
IL代码:

.method private hidebysig static void ConcatTest2() cil managed { // Code size 88 (0x58) .maxstack 4 .locals init (string V_0) IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: stloc.0 IL_0006: ldc.i4.s 9 IL_0008: newarr [System.Runtime]System.String IL_000d: dup IL_000e: ldc.i4.0 IL_000f: ldloc.0 IL_0010: stelem.ref IL_0011: dup IL_0012: ldc.i4.1 IL_0013: ldstr "1" IL_0018: stelem.ref IL_0019: dup IL_001a: ldc.i4.2 IL_001b: ldstr "2" IL_0020: stelem.ref IL_0021: dup IL_0022: ldc.i4.3 IL_0023: ldstr "3" IL_0028: stelem.ref IL_0029: dup IL_002a: ldc.i4.4 IL_002b: ldstr "4" IL_0030: stelem.ref IL_0031: dup IL_0032: ldc.i4.5 IL_0033: ldstr "5" IL_0038: stelem.ref IL_0039: dup IL_003a: ldc.i4.6 IL_003b: ldstr "6" IL_0040: stelem.ref IL_0041: dup IL_0042: ldc.i4.7 IL_0043: ldstr "7" IL_0048: stelem.ref IL_0049: dup IL_004a: ldc.i4.8 IL_004b: ldstr "8" IL_0050: stelem.ref IL_0051: call string [System.Runtime]System.String::Concat(string[]) IL_0056: stloc.0 IL_0057: ret
} // end of method Program::ConcatTest2

通过IL代码可以看出,string.Concat(s, s1, s2, s3)并不调用String.Concat方法,而是直接在堆栈上进行操作。因为需要局部变量来标记,比分次调用Concat方法所占的内存要多一些。
3.Format方法
3.1一次Format
private static void FormatTest() { string s = string.Empty; s = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", "1", "2", "3", "4", "5", "6", "7", "8"); }
运行时间:
内存情况:
IL代码:

.method private hidebysig static void FormatTest() cil managed { // Code size 88 (0x58) .maxstack 5 IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: pop IL_0006: ldstr "{0}{1}{2}{3}{4}{5}{6}{7}" IL_000b: ldc.i4.8 IL_000c: newarr [System.Runtime]System.Object IL_0011: dup IL_0012: ldc.i4.0 IL_0013: ldstr "1" IL_0018: stelem.ref IL_0019: dup IL_001a: ldc.i4.1 IL_001b: ldstr "2" IL_0020: stelem.ref IL_0021: dup IL_0022: ldc.i4.2 IL_0023: ldstr "3" IL_0028: stelem.ref IL_0029: dup IL_002a: ldc.i4.3 IL_002b: ldstr "4" IL_0030: stelem.ref IL_0031: dup IL_0032: ldc.i4.4 IL_0033: ldstr "5" IL_0038: stelem.ref IL_0039: dup IL_003a: ldc.i4.5 IL_003b: ldstr "6" IL_0040: stelem.ref IL_0041: dup IL_0042: ldc.i4.6 IL_0043: ldstr "7" IL_0048: stelem.ref IL_0049: dup IL_004a: ldc.i4.7 IL_004b: ldstr "8" IL_0050: stelem.ref IL_0051: call string [System.Runtime]System.String::Format(string, object[]) IL_0056: pop IL_0057: ret } // end of method Program::FormatTest

StringFormat方法虽然是基于StringBuilder,但由于需要遍历字符串来识别占位符,所以比较慢。
3.2Format分次拼接

private static void FormatTest2() { string s = string.Empty; s = string.Format("{0}{1}", s, "1"); s = string.Format("{0}{1}", s, "2"); s = string.Format("{0}{1}", s, "3"); s = string.Format("{0}{1}", s, "4"); s = string.Format("{0}{1}", s, "5"); s = string.Format("{0}{1}", s, "6"); s = string.Format("{0}{1}", s, "7"); s = string.Format("{0}{1}", s, "8"); }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void FormatTest2() cil managed { // Code size 143 (0x8f) .maxstack 3 .locals init (string V_0) IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: stloc.0 IL_0006: ldstr "{0}{1}" IL_000b: ldloc.0 IL_000c: ldstr "1" IL_0011: call string [System.Runtime]System.String::Format(string, object, object) IL_0016: stloc.0 IL_0017: ldstr "{0}{1}" IL_001c: ldloc.0 IL_001d: ldstr "2" IL_0022: call string [System.Runtime]System.String::Format(string, object, object) IL_0027: stloc.0 IL_0028: ldstr "{0}{1}" IL_002d: ldloc.0 IL_002e: ldstr "3" IL_0033: call string [System.Runtime]System.String::Format(string, object, object) IL_0038: stloc.0 IL_0039: ldstr "{0}{1}" IL_003e: ldloc.0 IL_003f: ldstr "4" IL_0044: call string [System.Runtime]System.String::Format(string, object, object) IL_0049: stloc.0 IL_004a: ldstr "{0}{1}" IL_004f: ldloc.0 IL_0050: ldstr "5" IL_0055: call string [System.Runtime]System.String::Format(string, object, object) IL_005a: stloc.0 IL_005b: ldstr "{0}{1}" IL_0060: ldloc.0 IL_0061: ldstr "6" IL_0066: call string [System.Runtime]System.String::Format(string, object, object) IL_006b: stloc.0 IL_006c: ldstr "{0}{1}" IL_0071: ldloc.0 IL_0072: ldstr "7" IL_0077: call string [System.Runtime]System.String::Format(string, object, object) IL_007c: stloc.0 IL_007d: ldstr "{0}{1}" IL_0082: ldloc.0 IL_0083: ldstr "8" IL_0088: call string [System.Runtime]System.String::Format(string, object, object) IL_008d: stloc.0 IL_008e: ret } // end of method Program::FormatTest2

分次使用Format方法拼接字符串,即分次调用Format方法,多次循环遍历字符串,耗时更长。
4.StringBuilder方法

private static void BuilderTest() { StringBuilder sb = new StringBuilder(); sb.Append("1"); sb.Append("2"); sb.Append("3"); sb.Append("4"); sb.Append("5"); sb.Append("6"); sb.Append("7"); sb.Append("8"); }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void BuilderTest() cil managed { // Code size 101 (0x65) .maxstack 3 IL_0000: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor() IL_0005: dup IL_0006: ldstr "1" IL_000b: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0010: pop IL_0011: dup IL_0012: ldstr "2" IL_0017: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_001c: pop IL_001d: dup IL_001e: ldstr "3" IL_0023: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0028: pop IL_0029: dup IL_002a: ldstr "4" IL_002f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0034: pop IL_0035: dup IL_0036: ldstr "5" IL_003b: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0040: pop IL_0041: dup IL_0042: ldstr "6" IL_0047: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_004c: pop IL_004d: dup IL_004e: ldstr "7" IL_0053: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0058: pop IL_0059: ldstr "8" IL_005e: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0063: pop IL_0064: ret } // end of method Program::BuilderTest

在短字符串大量拼接的测试中,可以看出一次使用+进行拼接所耗内存最少,所用时间最短。其余方式所耗内存相差不大,但StringBuilder所耗时间明显较短。
由于Format方法内部存在对字符串的遍历,可以推测,随着字符串的长度变长,Format方法所耗时间将会增加。
二、字符串变量拼接(多次循环拼接)

private static void TestPerformanceWithParam<T>(Action<T> action, T t, int times) { Stopwatch sw = new Stopwatch(); sw.Start(); for (int i = 0; i < times; i++) { action(t); } sw.Stop(); Console.WriteLine(action.Method.Name + ", FullTime: " + sw.ElapsedMilliseconds); }

1.+方法
1.1连续拼接
private static void AddTest(string t) { string s = string.Empty; s = t + t + t + t + t + t + t + t; }
运行时间:
内存情况:
IL代码:

.method private hidebysig static void AddTest(string t) cil managed { // Code size 51 (0x33) .maxstack 8 IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: pop IL_0006: ldc.i4.8 IL_0007: newarr [System.Runtime]System.String IL_000c: dup IL_000d: ldc.i4.0 IL_000e: ldarg.0 IL_000f: stelem.ref IL_0010: dup IL_0011: ldc.i4.1 IL_0012: ldarg.0 IL_0013: stelem.ref IL_0014: dup IL_0015: ldc.i4.2 IL_0016: ldarg.0 IL_0017: stelem.ref IL_0018: dup IL_0019: ldc.i4.3 IL_001a: ldarg.0 IL_001b: stelem.ref IL_001c: dup IL_001d: ldc.i4.4 IL_001e: ldarg.0 IL_001f: stelem.ref IL_0020: dup IL_0021: ldc.i4.5 IL_0022: ldarg.0 IL_0023: stelem.ref IL_0024: dup IL_0025: ldc.i4.6 IL_0026: ldarg.0 IL_0027: stelem.ref IL_0028: dup IL_0029: ldc.i4.7 IL_002a: ldarg.0 IL_002b: stelem.ref IL_002c: call string [System.Runtime]System.String::Concat(string[]) IL_0031: pop IL_0032: ret } // end of method Program::AddTest

从IL代码可见,在使用+连续拼接字符串变量时,内部调用了String.Concat(string[])方法。
1.2分段拼接

private static void AddWithParamTest2(string t) { string s = string.Empty; s += t; s += t; s += t; s += t; s += t; s += t; s += t; s += t; }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void AddWithParamTest2(string t) cil managed { // Code size 55 (0x37) .maxstack 8 IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: ldarg.0 IL_0006: call string [System.Runtime]System.String::Concat(string, string) IL_000b: ldarg.0 IL_000c: call string [System.Runtime]System.String::Concat(string, string) IL_0011: ldarg.0 IL_0012: call string [System.Runtime]System.String::Concat(string, string) IL_0017: ldarg.0 IL_0018: call string [System.Runtime]System.String::Concat(string, string) IL_001d: ldarg.0 IL_001e: call string [System.Runtime]System.String::Concat(string, string) IL_0023: ldarg.0 IL_0024: call string [System.Runtime]System.String::Concat(string, string) IL_0029: ldarg.0 IL_002a: call string [System.Runtime]System.String::Concat(string, string) IL_002f: ldarg.0 IL_0030: call string [System.Runtime]System.String::Concat(string, string) IL_0035: pop IL_0036: ret } // end of method Program::AddWithParamTest2

2.Concat方法
2.1分次concat
IL代码:

.method private hidebysig static void ConcatTest(string t) cil managed { // Code size 55 (0x37) .maxstack 8 IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: ldarg.0 IL_0006: call string [System.Runtime]System.String::Concat(string, string) IL_000b: ldarg.0 IL_000c: call string [System.Runtime]System.String::Concat(string, string) IL_0011: ldarg.0 IL_0012: call string [System.Runtime]System.String::Concat(string, string) IL_0017: ldarg.0 IL_0018: call string [System.Runtime]System.String::Concat(string, string) IL_001d: ldarg.0 IL_001e: call string [System.Runtime]System.String::Concat(string, string) IL_0023: ldarg.0 IL_0024: call string [System.Runtime]System.String::Concat(string, string) IL_0029: ldarg.0 IL_002a: call string [System.Runtime]System.String::Concat(string, string) IL_002f: ldarg.0 IL_0030: call string [System.Runtime]System.String::Concat(string, string) IL_0035: pop IL_0036: ret } // end of method Program::ConcatTest

从IL代码来看,同使用+分段拼接相似。
2.2一次拼接
IL代码:

.method private hidebysig static void ConcatTest2(string t) cil managed { // Code size 56 (0x38) .maxstack 4 .locals init (string V_0) IL_0000: ldsfld string [System.Runtime]System.String::Empty IL_0005: stloc.0 IL_0006: ldc.i4.s 9 IL_0008: newarr [System.Runtime]System.String IL_000d: dup IL_000e: ldc.i4.0 IL_000f: ldloc.0 IL_0010: stelem.ref IL_0011: dup IL_0012: ldc.i4.1 IL_0013: ldarg.0 IL_0014: stelem.ref IL_0015: dup IL_0016: ldc.i4.2 IL_0017: ldarg.0 IL_0018: stelem.ref IL_0019: dup IL_001a: ldc.i4.3 IL_001b: ldarg.0 IL_001c: stelem.ref IL_001d: dup IL_001e: ldc.i4.4 IL_001f: ldarg.0 IL_0020: stelem.ref IL_0021: dup IL_0022: ldc.i4.5 IL_0023: ldarg.0 IL_0024: stelem.ref IL_0025: dup IL_0026: ldc.i4.6 IL_0027: ldarg.0 IL_0028: stelem.ref IL_0029: dup IL_002a: ldc.i4.7 IL_002b: ldarg.0 IL_002c: stelem.ref IL_002d: dup IL_002e: ldc.i4.8 IL_002f: ldarg.0 IL_0030: stelem.ref IL_0031: call string [System.Runtime]System.String::Concat(string[]) IL_0036: stloc.0 IL_0037: ret } // end of method Program::ConcatTest2

从IL代码可以看出,同使用+一次拼接相似。
3.Format
private static void FormatTest(string t) { string s = string.Format("{0}{1}{2}{3}{4}{5}{6}{7}", t, t, t, t, t, t, t, t); }
运行时间:
内存情况:
IL代码:

.method private hidebysig static void FormatTest(string t) cil managed { // Code size 50 (0x32) .maxstack 8 IL_0000: ldstr "{0}{1}{2}{3}{4}{5}{6}{7}" IL_0005: ldc.i4.8 IL_0006: newarr [System.Runtime]System.Object IL_000b: dup IL_000c: ldc.i4.0 IL_000d: ldarg.0 IL_000e: stelem.ref IL_000f: dup IL_0010: ldc.i4.1 IL_0011: ldarg.0 IL_0012: stelem.ref IL_0013: dup IL_0014: ldc.i4.2 IL_0015: ldarg.0 IL_0016: stelem.ref IL_0017: dup IL_0018: ldc.i4.3 IL_0019: ldarg.0 IL_001a: stelem.ref IL_001b: dup IL_001c: ldc.i4.4 IL_001d: ldarg.0 IL_001e: stelem.ref IL_001f: dup IL_0020: ldc.i4.5 IL_0021: ldarg.0 IL_0022: stelem.ref IL_0023: dup IL_0024: ldc.i4.6 IL_0025: ldarg.0 IL_0026: stelem.ref IL_0027: dup IL_0028: ldc.i4.7 IL_0029: ldarg.0 IL_002a: stelem.ref IL_002b: call string [System.Runtime]System.String::Format(string, object[]) IL_0030: pop IL_0031: ret } // end of method Program::FormatTest

时间的损耗主要来自于String.Format方法。
4.StringBuilder方法

private static void BuilderTest(string t) { StringBuilder sb = new StringBuilder(); sb.Append(t); sb.Append(t); sb.Append(t); sb.Append(t); sb.Append(t); sb.Append(t); sb.Append(t); sb.Append(t); }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void BuilderTest(string t) cil managed { // Code size 69 (0x45) .maxstack 3 IL_0000: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor() IL_0005: dup IL_0006: ldarg.0 IL_0007: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_000c: pop IL_000d: dup IL_000e: ldarg.0 IL_000f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0014: pop IL_0015: dup IL_0016: ldarg.0 IL_0017: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_001c: pop IL_001d: dup IL_001e: ldarg.0 IL_001f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0024: pop IL_0025: dup IL_0026: ldarg.0 IL_0027: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_002c: pop IL_002d: dup IL_002e: ldarg.0 IL_002f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0034: pop IL_0035: dup IL_0036: ldarg.0 IL_0037: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_003c: pop IL_003d: ldarg.0 IL_003e: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_0043: pop IL_0044: ret } // end of method Program::BuilderTest

在短字符串(上面所用字符串为“short”)大量循环拼接(上述结果为每个方法循环执行一千万次)时,四种方法的差距并不明显。
当字符串变长后,可见运行结果差距拉大:
此时StringBuilder仍没有明显的优势。
三、字符串变量拼接(循环拼接至一个字符串)
1.+方法

private static void TestAddVeryLong(string s, int times) { Stopwatch sw = new Stopwatch(); sw.Start(); string str = string.Empty; for(int i = 0; i < times; i++) { str += s; } sw.Stop(); Console.WriteLine("add very long: " + sw.ElapsedMilliseconds); }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void TestAddVeryLong(string s, int32 times) cil managed { // Code size 71 (0x47) .maxstack 2 .locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0, string V_1, int32 V_2) IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start() IL_000c: ldsfld string [System.Runtime]System.String::Empty IL_0011: stloc.1 IL_0012: ldc.i4.0 IL_0013: stloc.2 IL_0014: br.s IL_0022 IL_0016: ldloc.1 IL_0017: ldarg.0 IL_0018: call string [System.Runtime]System.String::Concat(string, string) IL_001d: stloc.1 IL_001e: ldloc.2 IL_001f: ldc.i4.1 IL_0020: add IL_0021: stloc.2 IL_0022: ldloc.2 IL_0023: ldarg.1 IL_0024: blt.s IL_0016 IL_0026: ldloc.0 IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop() IL_002c: ldstr "add very long: " IL_0031: ldloc.0 IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds() IL_0037: box [System.Runtime]System.Int64 IL_003c: call string [System.Runtime]System.String::Concat(object, object) IL_0041: call void [System.Console]System.Console::WriteLine(string) IL_0046: ret } // end of method Program::TestAddVeryLong

2.Concat方法

private static void TestConcatVeryLong(string s, int times) { Stopwatch sw = new Stopwatch(); sw.Start(); string str = string.Empty; for (int i = 0; i < times; i++) { str = string.Concat(str, s); } sw.Stop(); Console.WriteLine("concat very long: " + sw.ElapsedMilliseconds); }

IL代码:

.method private hidebysig static void TestConcatVeryLong(string s, int32 times) cil managed { // Code size 71 (0x47) .maxstack 2 .locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0, string V_1, int32 V_2) IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start() IL_000c: ldsfld string [System.Runtime]System.String::Empty IL_0011: stloc.1 IL_0012: ldc.i4.0 IL_0013: stloc.2 IL_0014: br.s IL_0022 IL_0016: ldloc.1 IL_0017: ldarg.0 IL_0018: call string [System.Runtime]System.String::Concat(string, string) IL_001d: stloc.1 IL_001e: ldloc.2 IL_001f: ldc.i4.1 IL_0020: add IL_0021: stloc.2 IL_0022: ldloc.2 IL_0023: ldarg.1 IL_0024: blt.s IL_0016 IL_0026: ldloc.0 IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop() IL_002c: ldstr "concat very long: " IL_0031: ldloc.0 IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds() IL_0037: box [System.Runtime]System.Int64 IL_003c: call string [System.Runtime]System.String::Concat(object, object) IL_0041: call void [System.Console]System.Console::WriteLine(string) IL_0046: ret } // end of method Program::TestConcatVeryLong

由IL代码可见,和使用+性能相似。
3.Format方法

private static void TestFormatVeryLong(string s, int times) { Stopwatch sw = new Stopwatch(); sw.Start(); string str = string.Empty; for (int i = 0; i < times; i++) { str = string.Format("{0}{1}", str, s); } sw.Stop(); Console.WriteLine("format very long: " + sw.ElapsedMilliseconds); }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void TestFormatVeryLong(string s, int32 times) cil managed { // Code size 76 (0x4c) .maxstack 3 .locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0, string V_1, int32 V_2) IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start() IL_000c: ldsfld string [System.Runtime]System.String::Empty IL_0011: stloc.1 IL_0012: ldc.i4.0 IL_0013: stloc.2 IL_0014: br.s IL_0027 IL_0016: ldstr "{0}{1}" IL_001b: ldloc.1 IL_001c: ldarg.0 IL_001d: call string [System.Runtime]System.String::Format(string, object, object) IL_0022: stloc.1 IL_0023: ldloc.2 IL_0024: ldc.i4.1 IL_0025: add IL_0026: stloc.2 IL_0027: ldloc.2 IL_0028: ldarg.1 IL_0029: blt.s IL_0016 IL_002b: ldloc.0 IL_002c: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop() IL_0031: ldstr "format very long: " IL_0036: ldloc.0 IL_0037: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds() IL_003c: box [System.Runtime]System.Int64 IL_0041: call string [System.Runtime]System.String::Concat(object, object) IL_0046: call void [System.Console]System.Console::WriteLine(string) IL_004b: ret } // end of method Program::TestFormatVeryLong

4.StringBuilder方法

private static void TestBuilderVeryLong(string s, int times) { Stopwatch sw = new Stopwatch(); sw.Start(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < times; i++) { sb.Append(s); } sw.Stop(); Console.WriteLine("builder very long: " + sw.ElapsedMilliseconds); }

运行时间:
内存情况:
IL代码:

.method private hidebysig static void TestBuilderVeryLong(string s, int32 times) cil managed { // Code size 71 (0x47) .maxstack 2 .locals init (class [System.Runtime.Extensions]System.Diagnostics.Stopwatch V_0, class [System.Runtime]System.Text.StringBuilder V_1, int32 V_2) IL_0000: newobj instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::.ctor() IL_0005: stloc.0 IL_0006: ldloc.0 IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start() IL_000c: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor() IL_0011: stloc.1 IL_0012: ldc.i4.0 IL_0013: stloc.2 IL_0014: br.s IL_0022 IL_0016: ldloc.1 IL_0017: ldarg.0 IL_0018: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string) IL_001d: pop IL_001e: ldloc.2 IL_001f: ldc.i4.1 IL_0020: add IL_0021: stloc.2 IL_0022: ldloc.2 IL_0023: ldarg.1 IL_0024: blt.s IL_0016 IL_0026: ldloc.0 IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop() IL_002c: ldstr "builder very long: " IL_0031: ldloc.0 IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds() IL_0037: box [System.Runtime]System.Int64 IL_003c: call string [System.Runtime]System.String::Concat(object, object) IL_0041: call void [System.Console]System.Console::WriteLine(string) IL_0046: ret } // end of method Program::TestBuilderVeryLong

这个差距在拼接字符串更多的时候会更加明显。
拼接一千万次时,+方法运行一个多小时仍无法得出结果:
而StringBuilder只需要102ms。
+方法的问题在于由于string的特殊性,每次操作都将新开辟内存空间,随着字符串长度的增加、操作次数的增加等,+方法所耗费的内存会越来越大。
而StringBuilder则可以在原有的内存空间中进行修改和扩张,在进行频繁、长串的操作时极大地提高了效率。
显然,如果是不频繁、短字符串的拼接,使用哪种方式拼接字符串没有明显的性能差别(Format可能稍差一些),但如果是频繁的长串操作,StringBuilder具有绝对的优势。
C# 字符串拼接性能探索 c#中+、string.Concat、string.Format、StringBuilder.Append四种方式进行字符串拼接时的性能的更多相关文章
- Java 字符串拼接四种方式的性能比较分析
一.简单介绍 编写代码过程中,使用"+"和"contact"比较普遍,但是它们都不能满足大数据量的处理,一般情况下有一下四种方法处理字符串拼接,如下: 1. 加 ...
- 信1705-2 软工作业最大重复词查询思路: (1)将文章(一个字符串存储)按空格进行拆分(split)后,存储到一个字符串(单词)数组中。 (2)定义一个Map,key是字符串类型,保存单词;value是数字类型,保存该单词出现的次数。 (3)遍历(1)中得到的字符串数组,对于每一个单词,考察Map的key中是否出现过该单词,如果没出现过,map中增加一个元素,key为该单词,value为1(
通过学习学会了文本的访问,了解一点哈希表用途.经过网上查找做成了下面查询文章重复词的JAVA程序. 1 思 思路: (1)将文章(一个字符串存储)按空格进行拆分(split)后,存储到一个字符串(单词 ...
- C#批量插入数据到Sqlserver中的四种方式
我的新书ASP.NET MVC企业级实战预计明年2月份出版,感谢大家关注! 本篇,我将来讲解一下在Sqlserver中批量插入数据. 先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的 ...
- C#_批量插入数据到Sqlserver中的四种方式
先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记 ...
- String+ String.Concat String.Format StringBuilder 之间的性能测试
找到一篇国外的代码,专门来测试这个, String+ String.Concat String.Format StringBuilder 前三个在100个左右字符串差不多, String.Concat ...
- 城市经纬度 json 理解SignalR Main(string[] args)之args传递的几种方式 串口编程之端口 多线程详细介绍 递归一个List<T>,可自己根据需要改造为通用型。 Sql 优化解决方案
城市经纬度 json https://www.cnblogs.com/innershare/p/10723968.html 理解SignalR ASP .NET SignalR 是一个ASP .NET ...
- C#批量插入数据到Sqlserver中的四种方式 - 转
先创建一个用来测试的数据库和表,为了让插入数据更快,表中主键采用的是GUID,表中没有创建任何索引.GUID必然是比自增长要快的,因为你生成一个GUID算法所花的时间肯定比你从数据表中重新查询上一条记 ...
- 【Java EE 学习 80 下】【调用WebService服务的四种方式】【WebService中的注解】
不考虑第三方框架,如果只使用JDK提供的API,那么可以使用三种方式调用WebService服务:另外还可以使用Ajax调用WebService服务. 预备工作:开启WebService服务,使用jd ...
- JAVA中集合输出的四种方式
在JAVA中Collection输出有四种方式,分别如下: 一) Iterator输出. 该方式适用于Collection的所有子类. public class Hello { public stat ...
随机推荐
- html里 调整字间距
使用字与字的间距可设置letter-spacing属性实现,例如:1.p{letter-spacing:15px;}即表示<p>这是一段文字</p>标签里的文字间距为15px. ...
- backbone之collection
最近要用到backbone.js,网上也找了些资料,但是就看到一个开头还可以,往下看基本就看不下去了,幸好有这本书[LeanpubRead] Backbone.Marionette.js A Gent ...
- Selenium 2自动化测试实战40(单线程)
单线程 #onethread.py #coding:utf-8 from time import sleep,ctime #听音乐任务 def music(): print('i was listen ...
- unix进程通信方式总结(中)(转)
在上一篇博客http://blog.csdn.net/caoyan_12727/article/details/52049417已经总结了<<uinx环境高级编程>>进程通信前 ...
- React Native小知识点记录
1>查看 RN 的所有历史版本: npm view react-native versions -json 2>查看 RN 的当前版本: npm view react-native ver ...
- Java泛型(8):自限定&参数协变
自限定 自限定将强制泛型当做自己的边界参数来使用.自限定所做的,就是要求在继承关系中,像下面这样使用这个类: class A extends SelfBounded<A> {} 它的意义是 ...
- Windows WSL 安装OpenCV
安装WSL 启动WSL功能 首先启动WSL功能,下面提供两个办法 Powershell --> 管理员权限 --> 运行 Enable-WindowsOptionalFeature -On ...
- SpringBoot搭建聚合项目-实战记录01
工具:Spring Tool Suite 4 项目搭建 1.首先建立工作集 : Configure Working Sets -> New.. ->设置名称(如project) -> ...
- APP安全_Android反编译
反编译 Android的反编译工具:apktool,JEB等. Apk 文件的结构,如下: META-INF:签名文件 res:资源文件,里面的 xml 格式文件在编译过程中由文本格式转化为二进制的 ...
- 【Adobe Air程序开发】eclipse安装flash builder 4.7插件以及java、flex整合开发
看了看网上不少文章,发现很多内容都是很老的,没法用.故把自己的安装过程记录下来,方便以后使用 1.在这里,eclipse使用最新版eclipse juno 3.7 2.在adobe官网https:// ...