Ho preso in considerazione l'utilizzo delle Lazy<T>
proprietà per migliorare le prestazioni del mio codice (e per saperne di più su di esso). Sono venuto qui alla ricerca di risposte su quando usarlo ma sembra che ovunque io vada ci siano frasi come:
Utilizzare l'inizializzazione lenta per rinviare la creazione di un oggetto di grandi dimensioni o ad alta intensità di risorse o l'esecuzione di un'attività ad alta intensità di risorse, in particolare quando tale creazione o esecuzione potrebbe non verificarsi durante la durata del programma.
da MSDN Classe <T> pigra
Sono un po 'confuso perché non sono sicuro di dove disegnare la linea. Ad esempio, considero l'interpolazione lineare come un calcolo abbastanza veloce ma se non ho bisogno di farlo, l'inizializzazione pigra può aiutarmi a evitare di farlo e ne vale la pena?
Alla fine ho deciso di provare il mio test e ho pensato di condividere i risultati qui. Sfortunatamente non sono davvero un esperto nel fare questo tipo di test e quindi sono felice di ricevere commenti che suggeriscono miglioramenti.
Descrizione
Nel mio caso, ero particolarmente interessato a vedere se Lazy Properties potesse aiutare a migliorare una parte del mio codice che fa molta interpolazione (la maggior parte essendo inutilizzata) e quindi ho creato un test che ha confrontato 3 approcci.
Ho creato una classe di test separata con 20 proprietà di test (chiamiamole t-properties) per ogni approccio.
- Classe GetInterp: esegue l'interpolazione lineare ogni volta che viene ottenuta una proprietà t.
- Classe InitInterp: inizializza le proprietà t eseguendo l'interpolazione lineare per ognuna nel costruttore. Il get restituisce solo un doppio.
- Classe InitLazy: imposta le proprietà t come proprietà Lazy in modo che l'interpolazione lineare venga eseguita una volta quando viene acquisita la proprietà. I get successivi dovrebbero semplicemente restituire un doppio già calcolato.
I risultati del test sono misurati in ms e sono la media di 50 istanze o 20 proprietà ottenute. Ogni test è stato quindi eseguito 5 volte.
Risultati del test 1: istanziazione (media di 50 istanze)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.005668 0.005722 0.006704 0.006652 0.005572 0.0060636 6.72
InitInterp 0.08481 0.084908 0.099328 0.098626 0.083774 0.0902892 100.00
InitLazy 0.058436 0.05891 0.068046 0.068108 0.060648 0.0628296 69.59
Risultati del test 2: First Get (media di 20 proprietà)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.263 0.268725 0.31373 0.263745 0.279675 0.277775 54.38
InitInterp 0.16316 0.161845 0.18675 0.163535 0.173625 0.169783 33.24
InitLazy 0.46932 0.55299 0.54726 0.47878 0.505635 0.510797 100.00
Risultati del test 3: Second Get (media di 20 proprietà)
Class 1 2 3 4 5 Avg %
------------------------------------------------------------------------
GetInterp 0.08184 0.129325 0.112035 0.097575 0.098695 0.103894 85.30
InitInterp 0.102755 0.128865 0.111335 0.10137 0.106045 0.110074 90.37
InitLazy 0.19603 0.105715 0.107975 0.10034 0.098935 0.121799 100.00
osservazioni
GetInterp
è più veloce da istanziare come previsto perché non sta facendo nulla. InitLazy
è più veloce da istanziare rispetto a InitInterp
suggerire che l'overhead nell'impostazione delle proprietà pigre è più veloce del mio calcolo di interpolazione lineare. Tuttavia, sono un po 'confuso qui perché InitInterp
dovrebbero fare 20 interpolazioni lineari (per impostarne le proprietà t) ma ci GetInterp
vogliono solo 0,09 ms per istanziare (test 1), rispetto al quale ci vogliono 0,28 ms per fare solo un'interpolazione lineare la prima volta (test 2) e 0,1 ms per farlo la seconda volta (test 3).
Ci vuole InitLazy
quasi 2 volte di più rispetto GetInterp
a ottenere una proprietà la prima volta, mentre InitInterp
è la più veloce, perché ha popolato le sue proprietà durante l'istanza. (Almeno questo è ciò che avrebbe dovuto fare, ma perché il suo risultato di istanza è stato molto più rapido di una singola interpolazione lineare? Quando sta esattamente facendo queste interpolazioni?)
Sfortunatamente sembra che ci sia qualche ottimizzazione automatica del codice in corso nei miei test. Dovrebbe impiegare GetInterp
lo stesso tempo per ottenere una proprietà la prima volta come fa la seconda volta, ma sta mostrando come più di 2 volte più veloce. Sembra che questa ottimizzazione influisca anche sulle altre classi, dal momento che tutte impiegano la stessa quantità di tempo per il test 3. Tuttavia, tali ottimizzazioni possono anche aver luogo nel mio codice di produzione, che può anche essere una considerazione importante.
conclusioni
Mentre alcuni risultati sono come previsto, ci sono anche alcuni risultati inaspettati molto interessanti probabilmente dovuti all'ottimizzazione del codice. Anche per le classi che sembrano fare molto lavoro nel costruttore, i risultati dell'istanza mostrano che potrebbero essere ancora molto veloci da creare, rispetto all'ottenimento di una doppia proprietà. Mentre gli esperti in questo campo possono essere in grado di commentare e indagare più approfonditamente, la mia sensazione personale è che devo ripetere questo test, ma sul mio codice di produzione per esaminare quale tipo di ottimizzazioni potrebbero aver luogo anche lì. Tuttavia, mi aspetto che InitInterp
potrebbe essere la strada da percorrere.
get { if (foo == null) foo = new Foo(); return foo; }
. E ci sono miliardi di posti possibili per usarlo ...