Perché i campi pubblici sono più veloci delle proprietà?

Stavo Vector3 in XNA e ho visto che la class Vector3 campi pubblici anziché proprietà. Ho provato un rapido benchmark e ho scoperto che, per una 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ì.

Allora, perché è quello? So che una proprietà è compilata nei metodi get_X e set_X , il che comporterebbe un overhead di chiamata al metodo. Tuttavia, questi semplici getter / setter non sono sempre in linea con il 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; } ) ‘better’ OO-design di un campo pubblico? O meglio detto: come sono quei 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: Sto usando .NET 3.5 SP1 che credo abbia risolto problemi in cui i metodi con struct (o metodi di struct, non ne sono sicuro) non erano allineati, quindi non è così. Penso che lo sto usando almeno, è sicuramente installato, ma poi di nuovo, sto usando Vista 64-bit con SP1 che dovrebbe avere DX10.1 tranne che non ho DX10.1 ..

Inoltre: sì, ho eseguito un build di rilascio 🙂

EDIT : Apprezzo le risposte rapide ragazzi, ma ho indicato che so che un accesso alla proprietà è una chiamata al metodo, ma che non so perché il metodo, presumibilmente, allineato è più lento di un accesso diretto al campo.

EDIT 2 : Così ho creato un’altra struct che utilizzava metodi GetX () espliciti (o come non mi mancano affatto i miei giorni Java) e che ha eseguito lo stesso indipendentemente dal fatto che abbia disabilitato il rivestimento interno (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 il 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 ansible metodo, giusto? O è perché è ansible implementare un’interfaccia su di esso?

Questo è un peccato, dal momento che mi farà davvero pensare all’utilizzo di proprietà su cose critiche per le prestazioni, ma usare i campi mi fa sentire sporco e potrei scrivere quello che sto facendo in C.

EDIT 3 : ho trovato questo 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 si in- callvirt , nonostante fosse callvirt . Quindi sto diventando pazzo?

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

Ri: Edit3 – vedi 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. – 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!

Modifica 2:

Ho avuto un altro potenziale pensiero qui:

Hai detto che stai lavorando 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 prendevano structs come parametro non sarebbero mai state allineate su x86 prima di .net3.5sp1. Questo è praticamente irrilevante per questa discussione sul tuo sistema.


Modifica 3:

Un’altra cosa: il motivo per cui XNA utilizza i 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, dai un’occhiata al punto 2.


Per quanto riguarda il motivo per cui le proprietà automatiche sono migliori dei campi pubblici:

Consentono di modificare l’implementazione nella v2 della class e di aggiungere la logica alle routine get / set di proprietà secondo necessità, senza modificare l’interfaccia con gli utenti finali. Ciò può avere un profondo effetto sulla tua capacità di mantenere la libreria e il codice nel tempo.

—- Dal post originale – ma ho scoperto che non era questo il problema ——–

Stavi eseguendo una build di rilascio al di 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.

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

  • I campi pubblici sono assegnazioni dirette
  • Le proprietà sono metodi, quindi più codice, insignificante ma di più.

XNA ha come target XBox 360 e il JIT in .NET Compact Framework non è sofisticato come la sua controparte desktop. .NET CF JIT’er non imposterà i metodi di proprietà.

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, supponi 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. Esporlo attraverso una proprietà ti consente di modificare il codice di proprietà per aggiungere il tuo nuovo requisito ma non comporta modifiche inutili a nessun codice che lo acceda .