2016-01-29 13 views
6

Czytałem Improving .NET Application Performance and Scalability. Sekcja zatytułowana uniknięcia powtarzania pola lub właściwości dostęp zawiera wytycznych:Optymalizacja kompilatora właściwości, które pozostają statyczne przez czas trwania pętli

Jeśli używasz danych jest stały przez cały czas trwania pętli uzyskania go przed pętlą zamiast wielokrotnie dostępu do pola lub właściwości.

Poniższy kod jest podany jako przykład w ten sposób:

for (int item = 0; item < Customer.Orders.Count; item++) 
{ 
    CalculateTax(Customer.State, Customer.Zip, Customer.Orders[item]); 
} 

staje

string state = Customer.State; 
string zip = Customer.Zip; 
int count = Customers.Orders.Count; 
for (int item = 0; item < count; item++) 
{ 
    CalculateTax(state, zip, Customer.Orders[item]); 
} 

stanach artykułu:

pamiętać, że jeśli są to pola, to może być możliwe dla kompilatora do zrobić automatyczną optymalizację Lly. Jeśli są to właściwości, jest o wiele mniej prawdopodobne. Jeśli właściwości są wirtualne, nie można ich automatycznie wykonać.

Dlaczego jest "o wiele mniej prawdopodobne", aby właściwości zostały zoptymalizowane przez kompilator w ten sposób i kiedy można się spodziewać optymalizacji danej właściwości? Zakładam, że właściwości, w których dodatkowe operacje są wykonywane w akcesoriach, są trudniejsze do optymalizacji przez kompilator, i że te, które modyfikują tylko pole zaplecza, są bardziej prawdopodobnie zoptymalizowane, ale chciałbym jakieś bardziej konkretne reguły. Czy właściwości automatycznie wdrażane są zawsze zoptymalizowane?

Odpowiedz

3

Wymaga jitter zastosować dwa optymalizacje:

Pierwsza metoda nieruchomość getter musi być inlined więc okazuje do równowartości dostępu pola . To zwykle działa, gdy pobierający jest mały i nie rzuca wyjątków. Jest to konieczne, aby optymalizator mógł mieć pewność, że getter nie polega na stanie, na który może wpłynąć inny kod.

Należy zauważyć, że kod zoptymalizowany ręcznie byłby nieprawidłowy, gdyby na przykład indeksator Customer.Orders [] zmienił właściwość Customer.State. Leniwy kod taki jak ten jest oczywiście mało prawdopodobny, ale nie jest tak, jak nigdy dotąd :) Optymalizator musi być pewny.

Po drugie, kod dostępu do pola należy wyciągnąć z korpusu pętli. Optymalizacja zwana "niezmiennym ruchem kodu". Działa na prostym kodzie pobierającym właściwości, gdy jitter może dowieść, że instrukcje wewnątrz obiektu pętli nie mają wpływu na wartość.

Optymalizator jittera implementuje go, ale nie jest w nim gwiezdny. W tym konkretnym przypadku jest całkiem prawdopodobne, że zrezygnuje, gdy nie będzie w stanie zainicjować metody CalculateTax(). Natywny kompilator optymalizuje go znacznie agresywniej, może pozwolić sobie na spalenie pamięci i czasu analizy na nim. Optymalizator jittera musi spełnić dość trudny termin, aby uniknąć przerw.

Należy pamiętać o ograniczeniach optymalizatora, wykonując te czynności samodzielnie. Bardzo cholernie brzydki błąd, oczywiście jeśli te metody mają efekty uboczne, na które nie liczyliście. I tylko zrobić to, gdy profiler powiedział ci, że ten kod jest na gorącej ścieżce, typowe ~ 10% twojego kodu, który faktycznie wpływa na czas wykonania. Niskie kursy tutaj, zapytanie dbase, aby uzyskać dane o zamówieniu/zamówieniu, jest o rząd wielkości droższe niż obliczanie podatku. Na szczęście przekształcenie kodu w ten sposób powoduje również, że kod jest bardziej czytelny, więc zwykle dostajesz go za darmo. YMMV.

Program do optymalizacji jittera is here.

4

Dlaczego jest "o wiele mniej prawdopodobne", aby właściwości były optymalizowane przez kompilator w ten sposób i kiedy można się spodziewać optymalizacji danej właściwości?

Właściwości nie zawsze są tylko opakowaniami dla pola. Jeśli istnieje jakiś stopień logiki w nieruchomości, komplikatorowi staje się znacznie trudniejsze udowodnienie, że poprawne jest ponowne użycie wartości, którą uzyskał po uruchomieniu pętli.

Jako skrajny przykład, rozważmy

private Random rnd = new Random(); 
public int MyProperty 
{ 
    get { return rnd.Next(); } 
} 
+0

Nawet jeśli * to * po prostu zwróci wartość pola podkładu, kompilator będzie musiał udowodnić, że pole podkładu nie może się zmienić w całej pętli, a to jest trudne (często niemożliwe) do udowodnienia w w większości przypadków. – Servy

+0

@Servy: Tak, ale uważam, że jest to mniej więcej ten sam przypadek, co 'Zwróć uwagę, że jeśli są to pola, kompilator może automatycznie wykonać tę optymalizację' –

+0

Jeśli kompilator może udowodnić, że właściwość * tylko * zwraca wartość pola, * następnie * jest taka sama. Może lub nie może wiedzieć, czy nieruchomość właśnie to robi. – Servy