PDA

View Full Version : [Programmazione] Tempo di accesso alle variabili


Lim
29-09-2010, 10:55
Una buona consuetudine della programmazione ad oggetti consiglia di non rendere public le variabili di un oggetto, ma private e di accedervi tramite i metodi get()

Mi stavo chiedendo, ma il tempo di accesso nei due casi è lo stesso? (ne dubito)
Ragionando in termini di ottimizzazione del codice, conviene accedere direttamente alle variabili senza invocare un metodo aggiuntivo?

Esempio:

Assumiamo che un Oggetto abbia le variabili x ed y:

public int x;
public int y;

Per accedervi posso fare:
Oggetto.x;
Oggetto.y;

Se fossero private:
private int x;
private int y;

allora dovrei invocarle in quest'altro modo:
Oggetto.getX();
Oggetto.getY();




Supponiamo ancora di dovervi accedere migliaia di volte, sarebbero migliaia di chiamate a getX e getY, converrebbe bypassare queste chiamate al costo di una visibilità pubblica delle variabili in questione?

banryu79
29-09-2010, 11:31
...
Supponiamo ancora di dovervi accedere migliaia di volte, sarebbero migliaia di chiamate a getX e getY, converrebbe bypassare queste chiamate al costo di una visibilità pubblica delle variabili in questione?

So che programmi in Java, e relativamente a questo contesto tieni presente che le JVM moderne supportano la just-in-time compilation e quando, a runtime, un metodo viene invocato 1000 volte (di default, il parametro è personalizzabile) il codice viene compilato in forma nativa, per velocizzarne l'esecuzione.

In generale, che ci sia un "overhead" tra l'accesso diretto ad un membro di una istanza rispetto al'invocazione di un metodo, immagino di sì.
Sempre in generale, credo però non sia poi così rilevante.

Ma a meno di milioni (o forse centinaia di milioni, non certo migliaia) di invocazioni non credo la questione sia rilevante.
Se lo è e rappresenta il "collo di bottiglia" più rilevante tra quelli eventualmente presenti nell'applicazione (e per capirlo bisogna analizzare l'applicazione a runtime con un profiler) allora forse devi scegliere uno strumento più adatto (linguaggio di programmazione + sua implementazione) rispetto al contesto in cui lavori...

sottovento
29-09-2010, 11:57
Una buona consuetudine della programmazione ad oggetti consiglia di non rendere public le variabili di un oggetto, ma private e di accedervi tramite i metodi get()
...

Supponiamo ancora di dovervi accedere migliaia di volte, sarebbero migliaia di chiamate a getX e getY, converrebbe bypassare queste chiamate al costo di una visibilità pubblica delle variabili in questione?

I moderni compilatori si accorgono dell'uso di getter/setter sostituiscono direttamente il codice, pertanto non vedresti alcuna differenza di prestazioni.

E' diverso per compilatori piu' datati. Se per esempio in C non vuoi accedere direttamente ad una variabile globale ma proteggerla attraverso get/set, vedresti la differenza.

Lim
29-09-2010, 12:09
So che programmi in Java, e relativamente a questo contesto tieni presente che le JVM moderne supportano la just-in-time compilation e quando, a runtime, un metodo viene invocato 1000 volte (di default, il parametro è personalizzabile) il codice viene compilato in forma nativa, per velocizzarne l'esecuzione.

In generale, che ci sia un "overhead" tra l'accesso diretto ad un membro di una istanza rispetto al'invocazione di un metodo, immagino di sì.
Sempre in generale, credo però non sia poi così rilevante.

Ma a meno di milioni (o forse centinaia di milioni, non certo migliaia) di invocazioni non credo la questione sia rilevante.
Se lo è e rappresenta il "collo di bottiglia" più rilevante tra quelli eventualmente presenti nell'applicazione (e per capirlo bisogna analizzare l'applicazione a runtime con un profiler) allora forse devi scegliere uno strumento più adatto (linguaggio di programmazione + sua implementazione) rispetto al contesto in cui lavori...

Mi è venuto questo dubbio proprio perchè il profiler mi ha evidenziato un elevato numero di chiamate a specifici metodi get...

Comunque, stando a quanto dice Sottovento, posso lasciare tutto così com'è, penso che possa essere considerato un compilatore moderno il Java...

banryu79
29-09-2010, 13:02
Mi è venuto questo dubbio proprio perchè il profiler mi ha evidenziato un elevato numero di chiamate a specifici metodi get...

Comunque, stando a quanto dice Sottovento, posso lasciare tutto così com'è, penso che possa essere considerato un compilatore moderno il Java...

Quello che dice sottovento è senz'altro valido, ma tu resti comunque nell'ambito della tecnologia Java.

Il che significa che quello che javac (il compilatore) produce è bytecode.
Francamente non so se un setter "liscio" (cioè che nel corpo del metodo non fa altro che accedere al campo e basta) venga già tradotto a livello di bytecode come un accesso diretto al campo (perchè appunto il setter potrebbe anche fare altro) .
Immagino (e spero sinceramente) di sì, ma si fa presto a fare una prova e guardare il bytecode prodotto per togliersi il dubbio :D

Torav
29-09-2010, 13:31
Ma non si possono dare delle istruzioni per rendere inline le funzioni? Con gcc si può abbastanza facilmente e i getter e setter vengono sosituiti direttamente.

banryu79
29-09-2010, 13:50
Ma non si possono dare delle istruzioni per rendere inline le funzioni? Con gcc si può abbastanza facilmente e i getter e setter vengono sosituiti direttamente.
Non ce n'è bisogno: queste ottimizzazioni le fa la JVM, non il compilatore.
Ripeto: chi programma in un linguaggio che verrà tradotto da un compilatore in bytecode compatibile con la JVM non ha/ non deve (nel 95% dei casi?) preoccuparsi di questi aspetti.

Proprio perchè eventuali ottimizzazioni sono "spostate più in là" nella JVM a tempo di esecuzione (in questo modo si riescono a fare ottimizzazioni altrimenti impossibili a tempo di compilazione).

Poi magari ci sta che il compilatore specifico per il dato linguaggio (javac per Java, scalac per Scala, ecc...) sia abbastanza "smart" da ottimizzare certe casistiche (e qui conta quanto è avanzato il compilatore e le peculiarità del linguaggio; andando a naso direi che javac è bello maturo e dunque posso aspettarmi che sia più "smart" di altri compilatori più giovani).

Però non ho mai approfondito questi aspetti, dunque non so dare una risposta esauriente.

EDIT
@Lim: se vuoi sviscerare la questione ti consiglierei di consultare risorse "più specializzate", tipo i Java Technology Forums (http://forums.sun.com/index.jspa).
Comunque [sempre a naso] direri che per le ottimizzazioni in generale c'entra sia il compilatore (per via delle ottimizzazioni "statiche") che la JVM (e qui bisognerebbe anche conoscere quali opzioni si possono passare, già tra JVM -client e -server ci sono delle differenze).

A questo link (http://www.rhinocerus.net/forum/lang-java-programmer/587373-do-any-java-compilers-jvms-optimize-getter-method-calls.html) c'è una discussione recente (2009) in merito, pescata a caso dal web.
Dalla quale mi permetto di quotare una considerazione in particolare, che sposo completamente:

Given the infinitesimal advantage of direct calls, it seems you could focus
your optimization efforts elsewhere to much more advantage. I have always
found that a solid design is much more effective at achieving high
performance than speculative optimization. The exception to this rule would
be if profiling revealed that you were spending an inordinate amount of time
calling getters.

banryu79
29-09-2010, 14:34
Permettimi un'ulteriore riflessione.

Supponiamo che profilando l'applicazione scopri che hai un esagerazione di chiamate al metodo getQualcosa() di una tua (user-defined) classe.

Supponiamo anche che la cosa sia giustificata da un punto di vista logico: la tua classe in questione è una classe Punto che per esempio definisce un punto in un sistema di coordinate 3D e hai un motore che si mangia tonnellate di istanze di questa classe per leggerne (per esempio) le coordinate (getX(), getY(), getZ()) e fare qualcosa

Posto che la quantità industriale di accessi ai campi non è dovuto ad un problema di design, supponiamo che la classe sia immutabile: cioè lo stato di un Punto, una volta istanziato, non può essere modificato.

In questo caso è lecito supporre che le tre variabili che rappresentano il valore delle 3 coordinate siano dichiarate come final; a questo punto non è neccessario realizzare l'incapsulamento dello stato mettendo a disposizione i getter (i setter non ci saranno neppure, dato che l'oggetto è immutabile).

Avrai una cosa del genere:

public class Punto {
public final int x, y, z;

public Punto(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}

In questo caso definire una visibilità pubblica dello stato dell'oggetto, in quanto immutabile, non comporta problemi (ci sarebbero delle considerazioni circa il codice cliente che accede direttamente ai campi invece che indirettamente, tramite un metodo, ma sono questioni suppongo di minimo o nullo interesse nel tuo contesto)

Lim
29-09-2010, 14:41
Permettimi un'ulteriore riflessione.

Supponiamo che profilando l'applicazione scopri che hai un esagerazione di chiamate al metodo getQualcosa() di una tua (user-defined) classe.

Supponiamo anche che la cosa sia giustificata da un punto di vista logico: la tua classe in questione è una classe Punto che per esempio definisce un punto in un sistema di coordinate 3D e hai un motore che si mangia tonnellate di istanze di questa classe per leggerne (per esempio) le coordinate (getX(), getY(), getZ()) e fare qualcosa

Posto che la quantità industriale di accessi ai campi non è dovuto ad un problema di design, supponiamo che la classe sia immutabile: cioè lo stato di un Punto, una volta istanziato, non può essere modificato.

In questo caso è lecito supporre che le tre variabili che rappresentano il valore delle 3 coordinate siano dichiarate come final; a questo punto non è neccessario realizzare l'incapsulamento dello stato mettendo a disposizione i getter (i setter non ci saranno neppure, dato che l'oggetto è immutabile).

Avrai una cosa del genere:

public class Punto {
public final int x, y, z;

public Punto(int x, int y, int z) {
this.x = x;
this.y = y;
this.z = z;
}
}
Ed è lecito scegliere di avere una visibilità pubblica dello stato dell'oggetto, in quanto immutabile.



Con il tuo esempio non ci sei andato lontano!
Ho proprio una quantità industriale di "punti" da spostare, quindi ad ogni step temporale devo leggerne il centro (x,y,z) e le componenti della velocità (vx,vy,vz).
Purtroppo cambiano ad ogni step, quindi non posso dichiararle final ed i miei metodi get() mi restituiscono l'array di dim 3...

Ho fatto questa domanda proprio perchè il profiler mi evidenzia queste chiamate come quelle più esose in termini di selfTime e selfTime(CPU). Sto usando VisualVM... :rolleyes:

banryu79
29-09-2010, 15:12
Con il tuo esempio non ci sei andato lontano!
Ho proprio una quantità industriale di "punti" da spostare, quindi ad ogni step temporale devo leggerne il centro (x,y,z) e le componenti della velocità (vx,vy,vz).
Purtroppo cambiano ad ogni step, quindi non posso dichiararle final ed i miei metodi get() mi restituiscono l'array di dim 3...

Ho fatto questa domanda proprio perchè il profiler mi evidenzia queste chiamate come quelle più esose in termini di selfTime e selfTime(CPU). Sto usando VisualVM... :rolleyes:
Richiesta:

-> Puoi descrivere il tuo sistema e le relazioni tra le entità coinvolte in modo schematico e conciso, individuando bene ogni entità con un nome (a cui dopo, nel proseguio del thread, ci si possa riferire senza ambiguità) e le operazioni che compie? (so che lo hai già fatto in un altro thread, ma è meglio se rendi la cosa in modo schematico). Magari delineando bene come evolve il sistema nel tempo.

Il motivo della richiesta sta nel fatto che io ricordo vagamente il comportmento della tua applicazione e mi pare di capire che tu stia cercando di eseguire delle ottimizzazioni di "grana fine" perchè stai sviluppando una simulazione la cui bontà/validità è direttamente legata a parametri quantitativi che a loro volta implicano il consumo risorse macchina di grandezza proporzionale al numero delle entità simulate istanziate a runtime.

Per darti un consiglio efficace dunque (e io non sono sicuro di potertene dare uno, in tal senso) è neccessario avere un'idea precisa della composizione e del funzionamento del sistema, oltre che del fattore con cui consuma risorse macchina attualmente.