Zastanawiam się, jak kawałek zablokowanego kodu może spowolnić mój kod, mimo że kod nigdy nie jest wykonywany. Oto przykład poniżej:Jak uniknąć spowolnienia z powodu zablokowanego kodu?
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;
}
Ten kod działa w ~ 1300ms na moim komputerze. Jeśli usuniemy blokadę (ale zachowamy jej ciało), otrzymamy 750ms. Prawie podwójne, mimo że kod nigdy nie działa!
Oczywiście ten kod nic nie robi. Zauważyłem to podczas dodawania leniwego inicjowania w klasie, w której kod sprawdza, czy obiekt jest inicjowany i jeśli nie inicjuje go. Problem polega na tym, że inicjalizacja jest zablokowana i spowalnia wszystko, nawet po pierwszym wywołaniu.
Moje pytania są następujące:
- Dlaczego tak się dzieje?
- Jak uniknąć spowolnienia
Jeśli nie zamierzasz używać "blokady" intensywnie - nie martwiłbym się tym. – James
Otrzymuję podobne wyniki, ale tyknięcie to 100 * nano * -seconds. Oba przebiegi powinny zająć ~ 0ms (tzn. Jeśli wypiszesz 'sw.ElapseMilliseconds'.) To" spowolnienie "(z ~ 0.00006s) jest prawdopodobnie spowodowane tym, że' lock' zawiera blok 'try/finally', który prawdopodobnie jest konfiguracja po wywołaniu metody. Spróbuj umieścić zawartość 'testRand' w pętli; w tym momencie widać prawie * nie * spowolnienie. – dlev
Czy próbowałeś zaznaczyć metodę za pomocą 'AggressiveInline'? Być może kod blokujący spowodował, że metoda była zbyt duża dla normalnego wstawiania. JITter .net inline używa raczej głupiego heurystyki opartej na rozmiarze kodu IL. – CodesInChaos