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 8IL_0000: ldsfld string [System.Runtime]System.String::EmptyIL_0005: popIL_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 2IL_0000: ldsfld string [System.Runtime]System.String::EmptyIL_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: popIL_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 2IL_0000: ldsfld string [System.Runtime]System.String::EmptyIL_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: popIL_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::EmptyIL_0005: stloc.0IL_0006: ldc.i4.s 9IL_0008: newarr [System.Runtime]System.StringIL_000d: dupIL_000e: ldc.i4.0IL_000f: ldloc.0IL_0010: stelem.refIL_0011: dupIL_0012: ldc.i4.1IL_0013: ldstr "1"IL_0018: stelem.refIL_0019: dupIL_001a: ldc.i4.2IL_001b: ldstr "2"IL_0020: stelem.refIL_0021: dupIL_0022: ldc.i4.3IL_0023: ldstr "3"IL_0028: stelem.refIL_0029: dupIL_002a: ldc.i4.4IL_002b: ldstr "4"IL_0030: stelem.refIL_0031: dupIL_0032: ldc.i4.5IL_0033: ldstr "5"IL_0038: stelem.refIL_0039: dupIL_003a: ldc.i4.6IL_003b: ldstr "6"IL_0040: stelem.refIL_0041: dupIL_0042: ldc.i4.7IL_0043: ldstr "7"IL_0048: stelem.refIL_0049: dupIL_004a: ldc.i4.8IL_004b: ldstr "8"IL_0050: stelem.refIL_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 5IL_0000: ldsfld string [System.Runtime]System.String::EmptyIL_0005: popIL_0006: ldstr "{0}{1}{2}{3}{4}{5}{6}{7}"IL_000b: ldc.i4.8IL_000c: newarr [System.Runtime]System.ObjectIL_0011: dupIL_0012: ldc.i4.0IL_0013: ldstr "1"IL_0018: stelem.refIL_0019: dupIL_001a: ldc.i4.1IL_001b: ldstr "2"IL_0020: stelem.refIL_0021: dupIL_0022: ldc.i4.2IL_0023: ldstr "3"IL_0028: stelem.refIL_0029: dupIL_002a: ldc.i4.3IL_002b: ldstr "4"IL_0030: stelem.refIL_0031: dupIL_0032: ldc.i4.4IL_0033: ldstr "5"IL_0038: stelem.refIL_0039: dupIL_003a: ldc.i4.5IL_003b: ldstr "6"IL_0040: stelem.refIL_0041: dupIL_0042: ldc.i4.6IL_0043: ldstr "7"IL_0048: stelem.refIL_0049: dupIL_004a: ldc.i4.7IL_004b: ldstr "8"IL_0050: stelem.refIL_0051: call string [System.Runtime]System.String::Format(string,object[])IL_0056: popIL_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::EmptyIL_0005: stloc.0IL_0006: ldstr "{0}{1}"IL_000b: ldloc.0IL_000c: ldstr "1"IL_0011: call string [System.Runtime]System.String::Format(string,object,object)IL_0016: stloc.0IL_0017: ldstr "{0}{1}"IL_001c: ldloc.0IL_001d: ldstr "2"IL_0022: call string [System.Runtime]System.String::Format(string,object,object)IL_0027: stloc.0IL_0028: ldstr "{0}{1}"IL_002d: ldloc.0IL_002e: ldstr "3"IL_0033: call string [System.Runtime]System.String::Format(string,object,object)IL_0038: stloc.0IL_0039: ldstr "{0}{1}"IL_003e: ldloc.0IL_003f: ldstr "4"IL_0044: call string [System.Runtime]System.String::Format(string,object,object)IL_0049: stloc.0IL_004a: ldstr "{0}{1}"IL_004f: ldloc.0IL_0050: ldstr "5"IL_0055: call string [System.Runtime]System.String::Format(string,object,object)IL_005a: stloc.0IL_005b: ldstr "{0}{1}"IL_0060: ldloc.0IL_0061: ldstr "6"IL_0066: call string [System.Runtime]System.String::Format(string,object,object)IL_006b: stloc.0IL_006c: ldstr "{0}{1}"IL_0071: ldloc.0IL_0072: ldstr "7"IL_0077: call string [System.Runtime]System.String::Format(string,object,object)IL_007c: stloc.0IL_007d: ldstr "{0}{1}"IL_0082: ldloc.0IL_0083: ldstr "8"IL_0088: call string [System.Runtime]System.String::Format(string,object,object)IL_008d: stloc.0IL_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 3IL_0000: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()IL_0005: dupIL_0006: ldstr "1"IL_000b: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0010: popIL_0011: dupIL_0012: ldstr "2"IL_0017: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_001c: popIL_001d: dupIL_001e: ldstr "3"IL_0023: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0028: popIL_0029: dupIL_002a: ldstr "4"IL_002f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0034: popIL_0035: dupIL_0036: ldstr "5"IL_003b: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0040: popIL_0041: dupIL_0042: ldstr "6"IL_0047: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_004c: popIL_004d: dupIL_004e: ldstr "7"IL_0053: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0058: popIL_0059: ldstr "8"IL_005e: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0063: popIL_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 8IL_0000: ldsfld string [System.Runtime]System.String::EmptyIL_0005: popIL_0006: ldc.i4.8IL_0007: newarr [System.Runtime]System.StringIL_000c: dupIL_000d: ldc.i4.0IL_000e: ldarg.0IL_000f: stelem.refIL_0010: dupIL_0011: ldc.i4.1IL_0012: ldarg.0IL_0013: stelem.refIL_0014: dupIL_0015: ldc.i4.2IL_0016: ldarg.0IL_0017: stelem.refIL_0018: dupIL_0019: ldc.i4.3IL_001a: ldarg.0IL_001b: stelem.refIL_001c: dupIL_001d: ldc.i4.4IL_001e: ldarg.0IL_001f: stelem.refIL_0020: dupIL_0021: ldc.i4.5IL_0022: ldarg.0IL_0023: stelem.refIL_0024: dupIL_0025: ldc.i4.6IL_0026: ldarg.0IL_0027: stelem.refIL_0028: dupIL_0029: ldc.i4.7IL_002a: ldarg.0IL_002b: stelem.refIL_002c: call string [System.Runtime]System.String::Concat(string[])IL_0031: popIL_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 8IL_0000: ldsfld string [System.Runtime]System.String::EmptyIL_0005: ldarg.0IL_0006: call string [System.Runtime]System.String::Concat(string,string)IL_000b: ldarg.0IL_000c: call string [System.Runtime]System.String::Concat(string,string)IL_0011: ldarg.0IL_0012: call string [System.Runtime]System.String::Concat(string,string)IL_0017: ldarg.0IL_0018: call string [System.Runtime]System.String::Concat(string,string)IL_001d: ldarg.0IL_001e: call string [System.Runtime]System.String::Concat(string,string)IL_0023: ldarg.0IL_0024: call string [System.Runtime]System.String::Concat(string,string)IL_0029: ldarg.0IL_002a: call string [System.Runtime]System.String::Concat(string,string)IL_002f: ldarg.0IL_0030: call string [System.Runtime]System.String::Concat(string,string)IL_0035: popIL_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 8IL_0000: ldsfld string [System.Runtime]System.String::EmptyIL_0005: ldarg.0IL_0006: call string [System.Runtime]System.String::Concat(string,string)IL_000b: ldarg.0IL_000c: call string [System.Runtime]System.String::Concat(string,string)IL_0011: ldarg.0IL_0012: call string [System.Runtime]System.String::Concat(string,string)IL_0017: ldarg.0IL_0018: call string [System.Runtime]System.String::Concat(string,string)IL_001d: ldarg.0IL_001e: call string [System.Runtime]System.String::Concat(string,string)IL_0023: ldarg.0IL_0024: call string [System.Runtime]System.String::Concat(string,string)IL_0029: ldarg.0IL_002a: call string [System.Runtime]System.String::Concat(string,string)IL_002f: ldarg.0IL_0030: call string [System.Runtime]System.String::Concat(string,string)IL_0035: popIL_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::EmptyIL_0005: stloc.0IL_0006: ldc.i4.s 9IL_0008: newarr [System.Runtime]System.StringIL_000d: dupIL_000e: ldc.i4.0IL_000f: ldloc.0IL_0010: stelem.refIL_0011: dupIL_0012: ldc.i4.1IL_0013: ldarg.0IL_0014: stelem.refIL_0015: dupIL_0016: ldc.i4.2IL_0017: ldarg.0IL_0018: stelem.refIL_0019: dupIL_001a: ldc.i4.3IL_001b: ldarg.0IL_001c: stelem.refIL_001d: dupIL_001e: ldc.i4.4IL_001f: ldarg.0IL_0020: stelem.refIL_0021: dupIL_0022: ldc.i4.5IL_0023: ldarg.0IL_0024: stelem.refIL_0025: dupIL_0026: ldc.i4.6IL_0027: ldarg.0IL_0028: stelem.refIL_0029: dupIL_002a: ldc.i4.7IL_002b: ldarg.0IL_002c: stelem.refIL_002d: dupIL_002e: ldc.i4.8IL_002f: ldarg.0IL_0030: stelem.refIL_0031: call string [System.Runtime]System.String::Concat(string[])IL_0036: stloc.0IL_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 8IL_0000: ldstr "{0}{1}{2}{3}{4}{5}{6}{7}"IL_0005: ldc.i4.8IL_0006: newarr [System.Runtime]System.ObjectIL_000b: dupIL_000c: ldc.i4.0IL_000d: ldarg.0IL_000e: stelem.refIL_000f: dupIL_0010: ldc.i4.1IL_0011: ldarg.0IL_0012: stelem.refIL_0013: dupIL_0014: ldc.i4.2IL_0015: ldarg.0IL_0016: stelem.refIL_0017: dupIL_0018: ldc.i4.3IL_0019: ldarg.0IL_001a: stelem.refIL_001b: dupIL_001c: ldc.i4.4IL_001d: ldarg.0IL_001e: stelem.refIL_001f: dupIL_0020: ldc.i4.5IL_0021: ldarg.0IL_0022: stelem.refIL_0023: dupIL_0024: ldc.i4.6IL_0025: ldarg.0IL_0026: stelem.refIL_0027: dupIL_0028: ldc.i4.7IL_0029: ldarg.0IL_002a: stelem.refIL_002b: call string [System.Runtime]System.String::Format(string,object[])IL_0030: popIL_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 3IL_0000: newobj instance void [System.Runtime]System.Text.StringBuilder::.ctor()IL_0005: dupIL_0006: ldarg.0IL_0007: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_000c: popIL_000d: dupIL_000e: ldarg.0IL_000f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0014: popIL_0015: dupIL_0016: ldarg.0IL_0017: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_001c: popIL_001d: dupIL_001e: ldarg.0IL_001f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0024: popIL_0025: dupIL_0026: ldarg.0IL_0027: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_002c: popIL_002d: dupIL_002e: ldarg.0IL_002f: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0034: popIL_0035: dupIL_0036: ldarg.0IL_0037: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_003c: popIL_003d: ldarg.0IL_003e: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_0043: popIL_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.0IL_0006: ldloc.0IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()IL_000c: ldsfld string [System.Runtime]System.String::EmptyIL_0011: stloc.1IL_0012: ldc.i4.0IL_0013: stloc.2IL_0014: br.s IL_0022IL_0016: ldloc.1IL_0017: ldarg.0IL_0018: call string [System.Runtime]System.String::Concat(string,string)IL_001d: stloc.1IL_001e: ldloc.2IL_001f: ldc.i4.1IL_0020: addIL_0021: stloc.2IL_0022: ldloc.2IL_0023: ldarg.1IL_0024: blt.s IL_0016IL_0026: ldloc.0IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_002c: ldstr "add very long: "IL_0031: ldloc.0IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_0037: box [System.Runtime]System.Int64IL_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.0IL_0006: ldloc.0IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()IL_000c: ldsfld string [System.Runtime]System.String::EmptyIL_0011: stloc.1IL_0012: ldc.i4.0IL_0013: stloc.2IL_0014: br.s IL_0022IL_0016: ldloc.1IL_0017: ldarg.0IL_0018: call string [System.Runtime]System.String::Concat(string,string)IL_001d: stloc.1IL_001e: ldloc.2IL_001f: ldc.i4.1IL_0020: addIL_0021: stloc.2IL_0022: ldloc.2IL_0023: ldarg.1IL_0024: blt.s IL_0016IL_0026: ldloc.0IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_002c: ldstr "concat very long: "IL_0031: ldloc.0IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_0037: box [System.Runtime]System.Int64IL_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.0IL_0006: ldloc.0IL_0007: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Start()IL_000c: ldsfld string [System.Runtime]System.String::EmptyIL_0011: stloc.1IL_0012: ldc.i4.0IL_0013: stloc.2IL_0014: br.s IL_0027IL_0016: ldstr "{0}{1}"IL_001b: ldloc.1IL_001c: ldarg.0IL_001d: call string [System.Runtime]System.String::Format(string,object,object)IL_0022: stloc.1IL_0023: ldloc.2IL_0024: ldc.i4.1IL_0025: addIL_0026: stloc.2IL_0027: ldloc.2IL_0028: ldarg.1IL_0029: blt.s IL_0016IL_002b: ldloc.0IL_002c: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_0031: ldstr "format very long: "IL_0036: ldloc.0IL_0037: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_003c: box [System.Runtime]System.Int64IL_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.0IL_0006: ldloc.0IL_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.1IL_0012: ldc.i4.0IL_0013: stloc.2IL_0014: br.s IL_0022IL_0016: ldloc.1IL_0017: ldarg.0IL_0018: callvirt instance class [System.Runtime]System.Text.StringBuilder [System.Runtime]System.Text.StringBuilder::Append(string)IL_001d: popIL_001e: ldloc.2IL_001f: ldc.i4.1IL_0020: addIL_0021: stloc.2IL_0022: ldloc.2IL_0023: ldarg.1IL_0024: blt.s IL_0016IL_0026: ldloc.0IL_0027: callvirt instance void [System.Runtime.Extensions]System.Diagnostics.Stopwatch::Stop()IL_002c: ldstr "builder very long: "IL_0031: ldloc.0IL_0032: callvirt instance int64 [System.Runtime.Extensions]System.Diagnostics.Stopwatch::get_ElapsedMilliseconds()IL_0037: box [System.Runtime]System.Int64IL_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四种方式进行字符串拼接时的性能...相关推荐
- php字符串函数处理emoji,PHP中处理内容含有emoji表情的几种方式
方法1: 数据库.表用utf8mb4编码 utf8mb4是4字节的utf8编码,可完美兼容旧的3字节utf8字符集,并且可以直接存储emoji表情.如果要用这种方式解决问题,那么PHP的版本需要> ...
- JavaScript中字符串连接/拼接的四种方式
JavaScript中连接字符串的方式有4种,分别是使用加号运算符连接.使用${}配合反引号连接.使用concat()函数连接.使用join()函数连接. 1. 使用加号运算符 示例代码如下: let ...
- C++中4种方式把字符串和数字连接起来
C++中4种方式把字符串和数字连接起来 帅东 以前老用Java里面的String类,用过的人都知道好舒服,连接字符串和数字只需要用一个 + 号就可以了.在这里真的想把C++中string类+号功能加强 ...
- 字符串拼接的四种方式详解,代码测试
字符串拼接的四种方式 1. 使用+ 号进行字符串拼接 2. concat() 方法 3 .StringBuffer(线程安全,效率没有 StringBuilder 高) 4. StringBuilde ...
- 在 C# 中生成代码的四种方式——包括.NET 5中的Source Generators
Microsoft在最新的C#版本中引入了Source Generator.这是一项新功能,可以让我们在代码编译时生成源代码.在本文中,我将介绍四种C#中的代码生成方式,以简化我们的日常工作.然后,您 ...
- java 给对象创建实例_Java中创建(实例化)对象的五种方式
Java中创建(实例化)对象的五种方式1.用new语句创建对象,这是最常见的创建对象的方法. 2.通过工厂方法返回对象,如:String str = String.valueOf(23); 3.运用反 ...
- form表单、控制器中接收表单提交数据的4种方式
Form表单 这篇文章主要讲的是form表单的提交 之前我们接触过的form表单元素是在Bootstrap框架里面,这次也将用到Bootstrap框架去布局(见图表1)通过Bootstrap框架布局呈 ...
- 控制器中接收数据的四种方式
控制器中接收数据的四种方式: (仅限于个别的方式(get/post)有效) 通过形参的方式接收表单提交的数据(可以接收post与get提交的数据): 注释: GetData自己定义的方法名里面存入形参 ...
- java解析与生成json数据的四种方式,比如将json字符串转为json对象或json对象转为json字符串
文章目录 1. 详说json 1.1 何为json 1.2 json语法 2. Java解析与生成JSON的四种方式 2.1 传统方式 2.2 利用Jackson方式 2.3 利用Gson方式 2.4 ...
最新文章
- gitlab windows安装_gitlab pages之gitlab-runner 安装(windows)
- srm linux字符界面,如何使用srm安全的删除Linux中的文件
- Place the Guards
- oracle 挖掘日志,Oracle 日志挖掘(LogMiner)使用详解
- jemter的竞品分析
- css 文本两端对齐终极解决方案--一丝冰凉
- 李宏毅机器学习笔记day1
- win32汇编实现一个时钟
- mysql主从复制报错:the master has purged binary logs containing GTIDs that the slave requires
- word流程图怎么使箭头对齐_word 流程图 怎么把箭头对整齐啊?
- 【服务器数据恢复】服务器硬盘读写不稳定掉线,lun丢失的数据恢复案例
- 给文档加密,你懂多少?
- 英伟达NVIDIA驱动安装失败
- Vue中使用防抖与截流
- Muse UI遇到的坑
- 微信公众平台接口调试工具——蓝牙设备调试篇
- 穿过黑暗的夜,才懂黎明的晨
- 地方门户运营 最全思路10条
- 【更新中】人教版高一数学知识点汇总(必修1)
- 狄利克雷卷积_莫比乌斯反演及狄利克雷卷积
热门文章
- 对象转型(casting); 多态; static(静态);单例模式
- 深入分析同步工具类之AbstractQueuedSynchronizer
- 利用boost获取时间并格式化
- hoj 1640 Mobile phones //poj 1195 Mobile phones 二维树状数组
- 在线2-36进制转文本工具
- Hbase备份与恢复(快照技术)
- 嵌套RecyclerView左右滑动替代自定义view
- I.MX6 Android 设备节点权限
- MicroProfile变成了Eclipse MicroProfile
- 第一个spring冲刺团队贡献分(80分满分)