2016-01-29 15 views
6

Stavo leggendo Improving .NET Application Performance and Scalability. La sezione intitolata Evitare ripetitivo campo o la proprietà di accesso contiene una linea guida:Ottimizzazione del compilatore delle proprietà che rimangono statiche per la durata di un ciclo

Se si utilizzano i dati che è statico per tutta la durata del ciclo, ottenerla prima del ciclo anziché più volte l'accesso a un campo o una proprietà.

Il seguente codice è dato come un esempio di questo:

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

diventa

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]); 
} 

L'articolo afferma:

Nota che se questi sono i campi, è potrebbe essere possibile per il compilatore di fare questa ottimizzazione automatica lly. Se sono proprietà, è molto meno probabile . Se le proprietà sono virtuali, non può essere eseguito automaticamente .

Perché è "molto meno probabile" che le proprietà vengano ottimizzate dal compilatore in questo modo e quando è possibile che una particolare proprietà sia o non sia ottimizzata? Suppongo che le proprietà in cui vengono eseguite operazioni aggiuntive negli accessor siano più difficili da ottimizzare per il compilatore e che quelle che modificano solo un backing field abbiano maggiori probabilità di essere ottimizzate, ma vorrebbero regole più concrete. Le proprietà auto-implementate sono sempre ottimizzate?

risposta

3

Si richiede il jitter di applicare due ottimizzazioni:

Innanzitutto il metodo di proprietà getter deve essere inline in modo che diventi nell'equivalente di un accesso campo . Questo tende a funzionare quando il getter è piccolo e non genera eccezioni. Ciò è necessario in modo che l'ottimizzatore possa essere sicuro che il getter non si basi su uno stato che può essere influenzato da un altro codice.

Nota come il codice ottimizzato a mano sarebbe errato se, ad esempio, l'indicizzatore Customer.Orders [] alterasse la proprietà Customer.State. Il codice pigro come questo è abbastanza improbabile, ma non è mai stato così :) L'ottimizzatore deve essere sicuro.

In secondo luogo, il codice di accesso al campo deve essere estratto dal corpo del circuito. Un'ottimizzazione chiamata "movimento del codice invariante". Funziona su un codice getter di proprietà semplice quando il jitter può dimostrare che le istruzioni all'interno del corpo del ciclo non influiscono sul valore.

L'ottimizzatore di jitter lo implementa ma non è stellare. In questo caso particolare è molto probabile che si arrenderà quando non è in grado di allineare il metodo CalculateTax(). Un compilatore nativo lo ottimizza in modo molto più aggressivo, può permettersi di masterizzare la memoria e il tempo di analisi su di esso. L'ottimizzatore di jitter deve rispettare una scadenza piuttosto rigida per evitare le pause.

Tenere a mente i limiti dell'ottimizzatore quando lo si fa da soli. Ovviamente il brutto baco è dannoso se questi metodi do hanno effetti collaterali sui quali non hai fatto affidamento. E solo fai questo quando il profiler ti ha detto che questo codice si trova sul percorso hot, il tipico ~ 10% del tuo codice che influenza effettivamente il tempo di esecuzione. Scarse probabilità qui, la query dbase per ottenere dati cliente/ordine sta per ordini di grandezza più costosi rispetto al calcolo delle tasse. Fortunatamente le trasformazioni di codice come questa tendono a rendere il codice più leggibile, quindi di solito lo si ottiene gratuitamente. YMMV.

Uno sfondo su ottimizzazioni jitter is here.

4

Perché è "molto meno probabile" che le proprietà vengano ottimizzate dal compilatore in questo modo e quando è possibile che una particolare proprietà sia o non sia ottimizzata?

Le proprietà non sono sempre solo involucri per un campo. Se c'è un qualsiasi grado di logica in una proprietà, diventa molto più difficile per un compilatore dimostrare che è corretto riutilizzare il valore che ha ottenuto all'inizio del ciclo.

Come esempio estremo, considerare

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

E anche se * fa * restituisce semplicemente il valore di un campo di supporto, il compilatore dovrebbe dimostrare che il campo di supporto non può mai cambiare nel ciclo, e questa è una cosa difficile (spesso impossibile) da provare in la maggior parte dei casi. – Servy

+0

@Servy: Sì, ma credo che sia più o meno lo stesso di "Nota che se questi sono campi, potrebbe essere possibile per il compilatore eseguire automaticamente questa ottimizzazione" –

+0

Se il compilatore può provare che la proprietà * solo * restituisce il valore di un campo, * allora * è lo stesso. Può o non può sapere se la proprietà fa proprio questo. – Servy

Problemi correlati