if (x == null) x = new X();
Run Code Online (Sandbox Code Playgroud)
与
x = x ?? new X();
Run Code Online (Sandbox Code Playgroud)
这两个中哪一个实际上更高效?一旦编译完成,它们会有效地结束(结果会x = x;是NO-OP)吗?
Mar*_*ers 31
查看中间语言代码有一个区别:
.method private hidebysig instance void Method1() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldfld class X Program::x
L_0006: brtrue.s L_0013
L_0008: ldarg.0
L_0009: newobj instance void X::.ctor()
L_000e: stfld class X Program::x
L_0013: ret
}
.method private hidebysig instance void Method2() cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: ldarg.0
L_0002: ldfld class X Program::x
L_0007: dup
L_0008: brtrue.s L_0010
L_000a: pop
L_000b: newobj instance void X::.ctor()
L_0010: stfld class X Program::x
L_0015: ret
}
Run Code Online (Sandbox Code Playgroud)
这是我为了得到这个而编译的代码:
void Method1()
{
if (x == null) x = new X();
}
void Method2()
{
x = x ?? new X();
}
Run Code Online (Sandbox Code Playgroud)
为了确定哪个更快,你应该两个时间.
Method Initial condition Iterations per second --------------------------------------------------- NullCheck x is null 33 million Coalesce x is null 33 million NullCheck x is not null 40 million Coalesce x is not null 33 million
结论:
当x不为null时的差异看起来可能是由于空合并运算符将x的值分配回x(stfld在IL中),而stfld当x不为空时,null检查跳过指令.
两者都是如此之快,你必须有一个非常紧密的循环来注意到差异.如果您已使用数据分析代码,则应该只进行这些性能优化.不同的情况,不同版本的.NET,不同的编译器等可能会产生不同的结果.
如果有人想知道我如何得到这些结果或重现它们,这里是我使用的代码:
using System;
class X { }
class Program
{
private X x;
private X xNull = null;
private X xNotNull = new X();
private void Method1Null()
{
x = xNull;
if (x == null) x = xNotNull;
}
private void Method2Null()
{
x = xNull;
x = x ?? xNotNull;
}
private void Method1NotNull()
{
x = xNotNull;
if (x == null) x = xNotNull;
}
private void Method2NotNull()
{
x = xNotNull;
x = x ?? xNotNull;
}
private const int repetitions = 1000000000;
private void Time(Action action)
{
DateTime start = DateTime.UtcNow;
for (int i = 0; i < repetitions; ++i)
{
action();
}
DateTime end = DateTime.UtcNow;
Console.WriteLine(repetitions / (end - start).TotalSeconds);
}
private void Run()
{
Time(() => { Method1Null(); });
Time(() => { Method2Null(); });
Time(() => { Method1NotNull(); });
Time(() => { Method2NotNull(); });
Console.WriteLine("Finished");
Console.ReadLine();
}
private static void Main()
{
new Program().Run();
}
}
Run Code Online (Sandbox Code Playgroud)
免责声明:没有基准是完美的,这个bechmark 远非完美,主要是为了保持简单.我已经运行了许多不同的测试,例如使用不同顺序的方法,首先是有没有"预热",有不同的时间长度等等.我每次都得到大致相同的结果.我没有任何证据可以证明这种或那种方式,所以任何有利于一种方法或另一种方法的偏见都是偶然的.
没有interresting性能差异可言.最重要的是,if (x == null) x = new X();是更具有可读性.
回答你原来的问题:一个聪明的优化编译器将以与编译x = x ?? new X()相同的方式进行编译if (x == null) x = new X();.
因此,在编译器上留下微优化,并专注于代码可读性和清晰度.
更新:要了解有关优化实践的更多信息,请阅读维基百科上的这篇文章,然后就Google问题的性质而言,谷歌"过早优化是所有邪恶的根源".