if (x == null) x = new X();
gegen
x = x ?? new X();
Welche dieser beiden Varianten ist tatsächlich leistungsfähiger? Sind sie nach der Kompilierung im Grunde genommen dasselbe (würde x = x;
ein NO-OP als Ergebnis sein)?
if (x == null) x = new X();
gegen
x = x ?? new X();
Welche dieser beiden Varianten ist tatsächlich leistungsfähiger? Sind sie nach der Kompilierung im Grunde genommen dasselbe (würde x = x;
ein NO-OP als Ergebnis sein)?
Ein Blick auf den Code der Zwischensprache zeigt einen Unterschied:
.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
}
Hier ist der Code, den ich kompiliert habe, um dies zu erreichen:
void Method1()
{
if (x == null) x = new X();
}
void Method2()
{
x = x ?? new X();
}
Um sicher zu sein, was schneller ist, sollten Sie beide Zeiten messen.
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
Schlussfolgerung:
Der Unterschied, wenn x nicht null ist, könnte darauf zurückzuführen sein, dass der Null-Koaleszenz-Operator den Wert von x wieder x zuordnet ( stfld
in IL), während die Nullprüfung über die stfld
Anweisung, wenn x nicht null ist.
Beide sind so schnell, dass man schon einen muy enge Schleife, um den Unterschied zu bemerken. Sie sollten diese Art von Leistungsoptimierung nur vornehmen, wenn Sie Ihren Code mit Ihren Daten profiliert haben. Unterschiedliche Situationen, unterschiedliche Versionen von .NET, unterschiedliche Compiler usw. können zu unterschiedlichen Ergebnissen führen.
Falls jemand wissen möchte, wie ich zu diesen Ergebnissen gekommen bin oder sie reproduzieren möchte, hier ist der Code, den ich verwendet habe:
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();
}
}
Haftungsausschluss: Kein Benchmark ist perfekt, und dieser Benchmark ist weit von perfekt, hauptsächlich um die Dinge einfach zu halten. Ich habe zahlreiche verschiedene Tests durchgeführt, z. B. mit den Methoden in einer anderen Reihenfolge, mit und ohne vorheriges "Aufwärmen", über unterschiedlich lange Zeiträume usw. Ich erhalte jedes Mal ungefähr die gleichen Ergebnisse. Ich hatte nichts zu beweisen, weder das eine noch das andere, so dass jede Voreingenommenheit zugunsten der einen oder anderen Methode unbeabsichtigt ist.
Es gibt keine Interessant Leistungsunterschied überhaupt . Das Wichtigste ist, dass if (x == null) x = new X();
es viel besser lesbar .
Um Ihre ursprüngliche Frage zu beantworten: Ein intelligenter, optimierender Compiler würde kompilieren x = x ?? new X()
auf die gleiche Weise wie if (x == null) x = new X();
.
Überlassen Sie daher Mikro-Optimierungen dem Compiler und konzentrieren Sie sich auf die Lesbarkeit und Klarheit des Codes.
Aktualisierung: Weitere Informationen über Optimierungsverfahren finden Sie unter dieser Artikel auf wikipedia und dann, im Hinblick auf die Art Ihrer Frage, Google für "Vorzeitige Optimierung ist die Wurzel allen Übels" .
Wie andere bereits erwähnt haben, ist der Leistungsunterschied zwischen den beiden nicht so groß, aber es gibt einen wichtigen Unterschied zwischen den beiden, auch wenn er in Ihrem Beispiel nicht so offensichtlich ist.
if (x == null) x = new X();
erzeugt eine potentielle Wettlaufsituation, bei der x von einem anderen Thread zwischen der Prüfung auf Null und der Erstellung neu erstellt werden kann, wodurch ein Objekt verloren geht.
x = x ?? new X();
erstellt zuerst eine Kopie der Variablen, so dass es keine potenzielle Race Condition gibt.
Dies ist eher ein Problem in Situationen, in denen Sie auf das Objekt verweisen. Zum Beispiel:
if (x != null) x.DoSomething(); // this can cause a null reference exception
// if another thread nulls x between the check
// and the call to DoSomething()
(x = x ?? new X()).DoSomething() // this should be fine.
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.