2009-03-11 10 views
38

Stavo curiosando in XNA e ho visto che la classe Vector3 conteneva campi pubblici anziché proprietà. Ho provato un rapido benchmark e ho scoperto che, per un struct, la differenza è piuttosto drammatica (aggiungendo due Vettori insieme a 100 milioni di volte hanno preso 2.0s con proprietà e 1.4 secondi con campi). Per un tipo di riferimento, la differenza non sembra essere così grande ma è lì.Perché i campi pubblici sono più veloci delle proprietà?

Quindi, perché? So che una proprietà è compilata nei metodi get_X e set_X, che comporterebbero un overhead di chiamata del metodo. Tuttavia, questi semplici getter/setter sono sempre in linea con la JIT? So che non puoi garantire ciò che la JIT decide di fare, ma sicuramente questo è abbastanza alto nella lista delle probabilità? Cos'altro c'è che separa un campo pubblico da una proprietà a livello di macchina?

E una cosa che mi sono chiesto: come è una proprietà auto-implementata (public int Foo { get; set; }) 'migliore' design OO di un campo pubblico? O meglio detto: come sono questi due diversi? So che renderlo una proprietà è più facile con la riflessione, ma qualcos'altro? Scommetto che la risposta ad entrambe le domande è la stessa cosa.

BTW: io sto usando .NET 3.5 SP1 che credo problemi risolti in cui i metodi con le strutture (o metodi di le strutture, non sono sicuro) non sono stati allineati in-, in modo che non è vero. Penso che lo sto usando almeno, è sicuramente installato, ma ripeto, sto usando Vista 64-bit con SP1 che dovrebbe avere DX10.1 tranne che non ho DX10.1 ..

Inoltre: sì, sono stato in esecuzione una build di rilascio :)

EDIT: apprezzo le risposte rapide ragazzi, ma ho indicato che ho faccio sanno che un accesso proprietà è una chiamata di metodo, ma che i don' so perché il metodo presumibilmente allineato è più lento di un accesso diretto al campo.

EDIT 2: Così ho creato un altro struct che ha usato esplicitamente GetX() metodi (o come non mancano i miei giorni di Java affatto) e che ha effettuato lo stesso se ho disabilitato in-rivestimento su di esso (tramite [MethodImplAttribute(MethodImplOptions.NoInlining)]) o no, quindi conclusione: i metodi non statici apparentemente non sono mai in linea, nemmeno sulle strutture.

Ho pensato che c'erano delle eccezioni, in cui la JIT poteva optare per il richiamo del metodo virtuale. Perché questo non può accadere su strutture che non conoscono alcuna eredità e quindi una chiamata al metodo può solo indicare un possibile metodo, giusto? O è perché è possibile implementare un'interfaccia su di esso?

Questa è una specie di peccato, dal momento che davvero mi fanno pensare di utilizzare le proprietà su roba critica prestazioni, ma utilizzando i campi mi fa sentire sporca e tanto vale scrivere quello che sto facendo in C.

EDIT 3: Ho trovato lo this post sullo stesso identico argomento. La sua conclusione finale è che la chiamata di proprietà è stata ottimizzata. Avrei anche potuto giurare di aver letto molte volte che le semplici proprietà getter/setter saranno allineate, nonostante sia callvirt nell'IL. Quindi sto diventando pazzo?

EDIT 4: Reed Copsey ha postato la risposta in un commento qui sotto:

Re: Edit3 - vedi il mio commento aggiornamento: Credo che questo sia JIT x86 vs x64 problemi JIT. il JIT in x64 non è maturo. Mi aspetterei che la MS migliori rapidamente così come i sistemi a 64 bit stanno arrivando online ogni giorno. - Reed Copsey

E la mia risposta alla sua risposta:

Grazie, questa è la risposta! Ho provato a forzare una build x86 e tutti i metodi sono ugualmente veloci e molto più veloci di x64. Questo è molto scioccante per me, in realtà, non avevo idea di vivere nella fase della pietra sul mio sistema operativo a 64 bit. Includerò il tuo commento nella mia risposta in modo che risulti migliore. - JulianR

Grazie a tutti!

+0

Domanda: cosa succede se il campo è pubblico ma c'è anche una proprietà. E 'quindi in linea? – Quibblesome

+0

Non sembra, no. – JulianR

+1

Re: Edit3 - vedere il mio commento aggiornato: credo che questo sia x86 JIT vs x64 problemi JIT. il JIT in x64 non è maturo. Mi aspetterei che la MS migliori rapidamente così come i sistemi a 64 bit stanno arrivando online ogni giorno. –

risposta

15

Edit 2:

ho avuto un altro potenziale pensiero qui:

Lei ha detto che si esegue su x64. Ho testato lo stesso problema su x86 e ho visto le stesse prestazioni quando si utilizzavano proprietà auto vs. campi. Tuttavia, se ti guardi intorno su Connect e sui post di mailing list/forum, ci sono molti riferimenti online sul fatto che il JIT del CLR x64 è un codice diverso e ha caratteristiche di performance molto diverse rispetto al JIT x86. La mia ipotesi è che questo è un posto in cui x64 è ancora in ritardo.

Inoltre, FYI, la cosa struct/method/etc fissata in .net 3.5sp1 era sul lato x86, ed era il fatto che le chiamate di metodo che hanno preso structs come parametro non sarebbero mai state allineate su x86 prima di .net3 .5sp1. Questo è praticamente irrilevante per questa discussione sul tuo sistema.


Edit 3:

Un'altra cosa: Quanto al motivo per XNA sta usando campi. In realtà ero al Game Fest dove hanno annunciato XNA. Rico Mariani ha tenuto un discorso in cui ha sollevato molti degli stessi punti presenti nel suo blog. Sembra che gli XNA abbiano avuto idee simili quando hanno sviluppato alcuni degli oggetti principali. Vedere:

http://blogs.msdn.com/ricom/archive/2006/09/07/745085.aspx

In particolare, il check out 2 punti #.


Per quanto riguarda il motivo per cui le proprietà automatiche sono meglio di campi pubblici:

Essi consentono di modificare l'implementazione in v2 della classe, e aggiungere la logica nella proprietà routine get/set, se necessario, senza cambiare la tua interfaccia con i tuoi utenti finali. Ciò può avere un profondo effetto sulla tua capacità di mantenere la libreria e il codice nel tempo.

---- Da post originale - ma scoperto questo non era il problema --------

stava usando un rilascio costruire fuori di VS? Questa può essere una spiegazione del perché le cose non vengono ottimizzate. Spesso, se si esegue VS, anche una build di rilascio ottimizzata, il processo host VS disabilita molte funzioni del JIT. Ciò può causare cambiamenti nei benchmark delle prestazioni.

+0

Sì, ho provato a chiudere tutte le istanze di VS ed eseguire l'exe nella cartella Release, ma lo stesso risultato (sebbene entrambe le versioni siano leggermente più veloci al di fuori di VS). E sì, questo è un buon motivo per usare le proprietà anche se non si compila il get/set all'inizio :) – JulianR

+0

I casi di utilizzo migliori per i tipi di struttura sono quelli che servono per legare alcune variabili insieme con nastro adesivo (ad es. le coordinate di un punto).Se si suppone che una struct accetti qualsiasi coppia di interi e li segnali come X e Y, non c'è davvero alcun comportamento utile che una versione futura del tipo possa eventualmente aggiungere agli accessori di proprietà X e Y senza rompere le cose. È meglio avere una struttura che dica quello che è (un campo X e un campo Y), che mantenerlo "segreto". – supercat

3
  • campi pubblici sono assegnazioni dirette
  • proprietà sono i metodi, quindi più codice, insignificanti, ma di più.
+0

Sì, lo so come ho detto, ma quando un metodo getter/setter è in linea, non è l'accesso diretto al campo di supporto della proprietà? – JulianR

+0

Julian - sì, dovrebbe. Stavi correndo in VS, però? In tal caso, il progetto host di VS disabilita molte delle ottimizzazioni del JIT, anche se si tratta di una build di rilascio. Vedi il mio commento qui sotto. –

5

Dovresti leggere questo articolo di Vance. Entra nei dettagli sul perché i metodi non sono sempre delineati dalla JIT'er anche se sembra del tutto ovvio che dovrebbero essere.

http://blogs.msdn.com/vancem/archive/2008/08/19/to-inline-or-not-to-inline-that-is-the-question.aspx

+0

Ecco un documento che esamina il costo dell'inlining: sia il runtime che il costo di compliazione (con un focus su GC): http://cs.anu.edu.au/~Steve.Blackburn/pubs/papers/writebarrier-ismm- 2002.pdf –

3

XNA deve indirizzare la XBox 360, e il JIT in .NET Compact Framework non è così sofisticato come la sua controparte desktop. .NET CF JIT'er non imposterà i metodi di proprietà.

3

L'accesso a un campo è solo un riferimento di memoria mentre l'utilizzo di una proprietà sta effettivamente invocando un metodo e include l'overhead di chiamata di funzione. Il motivo per utilizzare le proprietà anziché i campi è quello di isolare il codice dalle modifiche e fornire una granularità migliore rispetto all'accesso. Non esponendo direttamente il tuo campo hai un maggiore controllo su come l'accesso è fatto. L'utilizzo di campi automatici consente di ottenere il tipico comportamento getter/setter ma crea la possibilità di modificarlo senza una successiva necessità di propagare le modifiche ad altre parti del codice.

Ad esempio, si supponga di voler modificare il codice in modo che l'accesso a un campo sia controllato dal ruolo dell'utente corrente. Se avessi esposto il campo pubblicamente, dovresti toccare ogni parte del codice che l'ha acceduta. L'esposizione di una proprietà consente di modificare il codice proprietà per aggiungere il nuovo requisito ma non comporta modifiche non necessarie a qualsiasi codice che lo acceda..