我一直在阅读不同的答案,其中字符串连接操作更好.我读到某处"+"内部调用string.Concat方法,string.Concat两者之间更快.当我查看IL代码时,它似乎没有提出上述陈述.
对于
string s1 = "1" + "2";
Run Code Online (Sandbox Code Playgroud)
IL代码
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] string s1)
IL_0000: nop
IL_0001: ldstr "12"
IL_0006: stloc.0
IL_0007: ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)
另外,我从IL代码中注意到"+"只初始化一个字符串,而string.Concat初始化两个字符串以连接.我也试过多个字符串.在使用内存方面,"+"似乎只使用一个字符串变量,而另一个选项在内部使用更多变量.
对于,
string s1 = string.concat("1", "2");
Run Code Online (Sandbox Code Playgroud)
IL代码
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 18 (0x12)
.maxstack 2
.locals init ([0] string s1)
IL_0000: nop
IL_0001: ldstr "1"
IL_0006: ldstr "2"
IL_000b: call string [mscorlib]System.String::Concat(string,
string)
IL_0010: stloc.0
IL_0011: ret
} // end of method Program::Main
Run Code Online (Sandbox Code Playgroud)
那么我们可以从上面的IL代码中得出结论,"+"比"string.Concat"更快,因为它使用较小的变量来执行相同的操作吗?
这种比较是错误的(假设您对字符串常量的串联不感兴趣).
在您的第一个片段中,连接已由C#编译器执行:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 8 (0x8)
.maxstack 1
.locals init ([0] string s1)
IL_0000: nop
IL_0001: ldstr "12" // The strings are already concatenated in the IL.
IL_0006: stloc.0
IL_0007: ret
}
Run Code Online (Sandbox Code Playgroud)
在您的第二个片段中,string.Concat保留的呼叫为:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 18 (0x12)
.maxstack 2
.locals init ([0] string s1)
IL_0000: nop
IL_0001: ldstr "1"
IL_0006: ldstr "2"
IL_000b: call string [mscorlib]System.String::Concat(string,
string)
IL_0010: stloc.0
IL_0011: ret
}
Run Code Online (Sandbox Code Playgroud)
因此,尝试使用常量来辨别两个片段的性能是没有意义的,因为您将获得非代表性的结果.
在一般情况下,C#编译器将+在字符串上编译一组运算符作为单个调用string.Concat.您可以通过使用变量而不是常量执行几乎相同的测试来验证这一点.
作为演示,请考虑这两种C#方法.一个用于+连接字符串:
static string Plus(string a, string b, string c)
{
return a + b + c;
}
Run Code Online (Sandbox Code Playgroud)
其他电话string.Concat:
static string Concat(string a, string b, string c)
{
return string.Concat(a, b, c);
}
Run Code Online (Sandbox Code Playgroud)
现在使用Debug配置查看它们各自的IL:
.method private hidebysig static string Plus (
string a,
string b,
string c
) cil managed
{
.locals init (
[0] string V_0
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: ldarg.2
IL_0004: call string [mscorlib]System.String::Concat(string, string, string)
IL_0009: stloc.0
IL_000a: br.s IL_000c
IL_000c: ldloc.0
IL_000d: ret
}
Run Code Online (Sandbox Code Playgroud)
和:
.method private hidebysig static string Concat (
string a,
string b,
string c
) cil managed
{
.locals init (
[0] string V_0
)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldarg.1
IL_0003: ldarg.2
IL_0004: call string [mscorlib]System.String::Concat(string, string, string)
IL_0009: stloc.0
IL_000a: br.s IL_000c
IL_000c: ldloc.0
IL_000d: ret
}
Run Code Online (Sandbox Code Playgroud)
它们是相同的(除了它们的名字).如果我们使用Release配置构建,我们会得到更短的IL - 但两种方法仍然相同.
总之,在这种特殊情况下,我们可以安全地假设我们不会观察到表达同一事物的两种方式之间的任何性能差异.
在一般情况下(IL不相同或几乎相同),我们不能基于CLR的心理模型对性能做出任何假设.即使我们确实有一个完全准确的CLR心智模型,我们也必须考虑到字节码最终得到编译的机器代码,这与IL不同(例如,x86代码有寄存器,但IL没有).
为了提高性能,我们使用分析器,因为它们可以为我们提供实用,详细的指标.
| 归档时间: |
|
| 查看次数: |
437 次 |
| 最近记录: |