Ich frage mich, wie ein Stück gesperrten Code meinen Code verlangsamen kann, obwohl der Code nie ausgeführt wird. Hier ist ein Beispiel unten:Wie kann man Verlangsamung aufgrund von gesperrtem Code vermeiden?
public void Test_PerformanceUnit()
{
Stopwatch sw = new Stopwatch();
sw.Start();
Random r = new Random();
for (int i = 0; i < 10000; i++)
{
testRand(r);
}
sw.Stop();
Console.WriteLine(sw.ElapsedTicks);
}
public object testRand(Random r)
{
if (r.Next(1) > 10)
{
lock(this) {
return null;
}
}
return r;
}
Dieser Code läuft in ~ 1300ms auf meinem Rechner. Wenn wir den Sperrblock entfernen (aber seinen Körper behalten), erhalten wir 750ms. Fast das Doppelte, obwohl der Code nie ausgeführt wird!
Natürlich tut dieser Code nichts. Ich habe es bemerkt, während ich in einer Klasse, in der der Code überprüft, ob das Objekt initialisiert ist und wenn es nicht initialisiert wird, etwas träge Initialisierung hinzufügt. Das Problem ist, dass die Initialisierung gesperrt ist und alles sogar nach dem ersten Aufruf verlangsamt wird.
Meine Fragen sind:
- Warum ist das passiert?
- Wie die Verlangsamung zu vermeiden
Wenn Sie nicht vorhaben, "Lock" intensiv zu benutzen - ich würde mich nicht wirklich darum kümmern. – James
Ich bekomme ähnliche Ergebnisse, aber ein Tick ist 100 * Nano * -Sekunden. Beide Läufe sollten ~ 0ms dauern (dh wenn Sie 'sw.ElapseMilliseconds' drucken). Diese" Verlangsamung "(von ~ 0.00006s) ist wahrscheinlich auf die Tatsache zurückzuführen, dass' lock' einen 'try/finally'-Block enthält, was wahrscheinlich der Fall ist Setup, wenn die Methode aufgerufen wird. Versuchen Sie, den Inhalt von "testRand" in die Schleife selbst zu stellen; Sie werden zu diesem Zeitpunkt fast * keine * Verlangsamung sehen. – dlev
Haben Sie versucht, die Methode mit 'AggressiveInline' zu markieren? Vielleicht hat der Sperrcode die Methode für normales Inlining zu groß gemacht. Die .net JITter-Inlines verwenden eine ziemlich dumme Heuristik basierend auf der Größe des IL-Codes. – CodesInChaos