2010-07-16 24 views
21

Ho letto da qualche parte che avere proprietà pubbliche è preferibile avere membri pubblici in una classe.Sovraccarico delle prestazioni per le proprietà in .NET

  1. È solo a causa di abstaraction e modularità? Ci sono altri motivi per evitare

  2. Gli accessi di proprietà sono configurati in chiamate di funzione dal compilatore. Per le proprietà senza un archivio di backup (ad esempio public string UserName { get; set; }), quale sarebbe l'overhead delle prestazioni rispetto a un accesso diretto ai membri? (Lo so che non dovrebbe in genere fare la differenza, ma in alcuni del mio codice, le proprietà sono accessibili milioni di volte.)

Edit1: Ho eseguito un codice di prova sui membri interi e proprietà ei membri pubblici erano circa 3-4 volte più veloci delle proprietà. (~ 57 ms vs ~ 206 ms in Debug e 57 vs 97 in Release era il valore di esecuzione più comune). Per 10 milioni di letture e scritture, entrambi sono abbastanza piccoli da non giustificare il cambiamento di qualcosa.

Codice:

class TestTime1 
{ 
    public TestTime1() { } 
    public int id=0; 
} 
class TestTime2 
{ 
    public TestTime2() { } 
    [DefaultValue(0)] 
    public int ID { get; set; } 
} 


class Program 
{ 
    static void Main(string[] args) 
    { 
     try 
     { 
      TestTime1 time1 = new TestTime1(); 
      TestTime2 time2 = new TestTime2(); 
      Stopwatch watch1 = new Stopwatch(); 
      Stopwatch watch2 = new Stopwatch(); 
      watch2.Start(); 
      for (int i = 0; i < 10000000; i++) 
      { 
       time2.ID = i; 
       i = time2.ID; 
      } 
      watch2.Stop(); 
      watch1.Start(); 
      for (int i = 0; i < 10000000; i++) 
      { 
       time1.id = i; 
       i = time1.id; 
      } 
      watch1.Stop(); 
      Console.WriteLine("Time for 1 and 2 : {0},{1}",watch1.ElapsedMilliseconds,watch2.ElapsedMilliseconds); 

     } 
     catch (Exception ex) 
     { 
      Console.WriteLine(ex.Message); 
     } 
     Console.In.ReadLine(); 
    } 
} 
+0

Serializzazione e DataBinding sono la ragione per cui posso pensare a – LiFo

+4

La differenza di fattore per la build di debug non ottimizzata è irrilevante. Non stai spedendo il build di debug ai clienti. Inoltre, noto che nel tuo test stai misurando * ora jit della proprietà * e * tempo di accesso *. Se sei interessato al costo * ammortizzato * di una proprietà jitted compreso il tempo di avvio del jitter, questa è una cosa. Ma se ciò che ti interessa è il costo * per utilizzo *, allora * non configura il costo jit con il costo per utilizzo * come fai qui. E indipendentemente dal fatto che la tua tecnica di misurazione sia buona: ottimizza * la cosa più lenta *. Dubito che sia così. –

+0

possibile duplicato di [Perché i campi pubblici sono più veloci delle proprietà?] (Http://stackoverflow.com/questions/632831/why-are-public-fields-faster-than-properties) – nawfal

risposta

9

È solo a causa di abstaraction e modularità? Ci sono altri motivi per evitare

Non che io sappia; queste ragioni sono di per sé abbastanza convincenti. Ma forse qualcun altro salterà su questo.

Gli accessi di proprietà sono configurati in chiamate di funzione dal compilatore. Per le proprietà senza un archivio di backup (ad esempio, public string UserName {get; set;}), quale sarebbe l'overhead delle prestazioni rispetto a un accesso diretto ai membri? (Lo so che non dovrebbe in genere fare la differenza, ma in alcuni del mio codice, le proprietà sono accessibili milioni di volte.)

Nel risultante Intermediate Language, un accesso alle proprietà è tradotto in una chiamata di metodo. Tuttavia, come dice la parola, questo è solo un linguaggio intermedio: viene compilato Just-In-Time su qualcos'altro. Questo passaggio di traduzione comporta anche ottimizzazioni come l'inlining di metodi banali, come semplici accessi alle proprietà.

Mi aspetterei (ma è necessario testare per assicurarsi) che JITter si prenda cura di tali accessori, quindi non ci dovrebbero essere differenze di prestazioni.

+1

Ecco uno dei motivi: dettare gli standard .NET che non devi esporre un campo come pubblico, con pochissime eccezioni. Per quanto riguarda l'inlining, vedi il mio commento ad Adam. –

+7

Gli standard dettano questo per un motivo, e penso che sia la ragione che stiamo cercando, non "perché Microsoft dice così" :) – Thomas

+0

Vorrei sottolineare (ad esempio boldify) l'inlinging, come AFAIK è il caso di tutte le proprietà sia su Mono che su CLR. – Dykam

4

E 'principalmente per scopi di astrazione (in seguito è possibile aggiungere la convalida senza rompere il codice esistente, o che richiedono ricompilazione).

Anche quando si utilizzano le proprietà automatiche, esiste ancora un campo di supporto generato dal compilatore e verrà eseguito come tale.

17

Non preoccuparti del sovraccarico delle prestazioni. È così piccolo che non dovresti considerare di indebolire l'incapsulamento della classe; sarebbe l'ottimizzazione prematura del peggiore tipo.

1

1) È per i principi di incapsulamento, ma altre funzioni .NET utilizzano proprietà come l'associazione dati.

2) Non sono sicuro di essere d'accordo, Ho sempre sentito che se la proprietà è un get/set lineare, è veloce come un accesso standard al campo - il compilatore lo fa per te.

Aggiornamento: sembra essere un po 'di entrambi, viene compilato per chiamare il metodo ma ottimizzato per JIT. Ad ogni modo, questo tipo di problema prestazionale non avrà un impatto significativo sul tuo codice. Tuttavia, si noti che la guida per implementare le proprietà è di renderle il più leggere possibile, che i chiamanti non sono attesi costosi.

+0

Ci sono più dettagli a questo. Credo che possa solo integrare la chiamata quando il chiamante e la proprietà sono definiti nello stesso assembly, ad esempio. Ma, davvero, non importa. L'overhead di chiamata non è nulla in confronto a quello che ottieni dall'essere in grado di sostituire un campo sottostante con tutta la logica di cui hai bisogno. –

+0

Strano, questo è un dettaglio piuttosto strano per non delinearlo - deludente in un certo senso lol. Come accennato, il decremento delle prestazioni, sia compilato che non, è trascurabile –

+0

Concordato in merito all'irrilevanza delle prestazioni, ma penso che ci sia un senso alla limitazione. Quando genera un codice CIL per la chiamata di proprietà, il compilatore deve avere accesso all'implementazione in modo che possa confermare che c'è solo un'assegnazione a una variabile di supporto e in modo che possa identificare quella variabile. In altre parole, questa ottimizzazione fa parte della compilazione originale, non quella finale di JIT. –

0

Dopo aver pubblicato il post this, ho capito che è fondamentalmente per nascondere il funzionamento interno dell'oggetto.

20

L'esecuzione del test 20 volte di fila, assicurando che l'ottimizzazione JIT è attivato nella build di rilascio:

Time for 1 and 2 : 47,66 
Time for 1 and 2 : 37,42 
Time for 1 and 2 : 25,36 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 27,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 26,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 
Time for 1 and 2 : 25,25 

Sì, il jitter è che bravo a inlining accesso alle proprietà. Perf è un non-problema e non dovrebbe mai essere considerato.

+1

+1 per metterlo alla prova. –

+0

Hmm ... ha eseguito il test nel debug invece che nel rilascio. Colpa mia! – apoorv020

+0

Nel rilascio, c'è ancora un overhead dell'80% sulla mia macchina. La mia macchina è a 32 bit, ho visto alcune strane differenze di prestazioni tra 32-bit e 64-bit. – apoorv020

0

Ho chiesto il same question prima.

Suppongo che stai usando VS2008, stai utilizzando un sistema operativo a 64 bit e la compilazione è impostata su "Qualsiasi CPU"? In tal caso, le proprietà non vengono evidenziate dal compilatore JIT x64. Fanno su 32-bit, rendendoli identici nelle prestazioni ai campi pubblici.

2

Assicurati di utilizzare Ctrl-F5 anziché F5; in caso contrario, il debugger verrà comunque collegato e alcune ottimizzazioni potrebbero non funzionare allo stesso modo, anche in modalità di rilascio. Almeno questo è il caso sulla mia macchina: F5 dà risultati simili a quelli che hai postato, mentre Ctrl-F5 dà risultati uguali.

0

Se si desidera un esempio specifico di proprietà che non sono necessarie per le variabili membro regolari, pensare all'ereditarietà: se una classe utilizza un membro pubblico, le derivazioni di questa classe non possono implementare la convalida o altro getter/comportamento setter. Sono bloccati con la variabile così com'è, e se vogliono fare qualcosa di diverso, devono 1) ignorare la variabile membro esistente e creare una nuova proprietà, 2) aggiungere una nuova proprietà e 3) sovrascrivere ogni metodo che chiamato o invocato la variabile membro per utilizzare invece la proprietà. Non solo è questo lavoro inutilmente più, se la persona che scrive la classe derivata non ha accesso alla fonte potrebbe essere quasi impossibile.

Se la classe base utilizza proprietà anziché variabili membro, è solo una questione di aggiungere la convalida o altri comportamenti alla funzione get/set e il gioco è fatto.

Problemi correlati