2013-02-04 12 views
6

Cosa c'è di meglio nel ciclo forJava per le prestazioni ciclo

questo:

for(int i = 0; i<someMethod(); i++) 
{//some code 
} 

o:

int a = someMethod(); 
for(int i = 0; i<a; i++) 
{//some code 
} 

Diciamo solo che someMethod() restituisce qualcosa di grande.

Primo metodo eseguirà someMethod() in ogni ciclo diminuendo così la velocità, secondo è più veloce ma diciamo che ci sono molti cicli simili a applicazione in modo che dichiara una vill variabile consuma più memoria.

Quindi cosa è meglio, o sto solo pensando stupidamente.

+0

In il tuo esempio 'a' è una variabile locale, quindi consuma memoria solo mentre l'esecuzione è all'interno del blocco in cui è definita. –

risposta

11

Il secondo è migliore, supponendo che someMethod() non abbia side effects.
In realtà memorizza nella cache il valore calcolato da someMethod(), quindi non sarà necessario ricalcolarlo (presupponendo che si tratti di un'opzione relativamente estesa).

Se lo fa (ha effetti collaterali) - i due scatta codice non sono equivalenti - e si dovrebbe fare ciò che è corretto .

Per quanto riguarda la "dimensione per la variabile un" - non è un problema in ogni caso, il ritornato valore someMethod() ha bisogno di essere memorizzati su qualche variabile temporanea intermedia comunque prima del calcolo (e anche se non era il caso, la dimensione di un intero è trascurabile).

P.S.
In alcuni casi, il compilatore/ottimizzatore JIT potrebbe ottimizzare il primo codice nel secondo, presupponendo ovviamente nessun effetto collaterale.

+0

Grazie, bellissima spiegazione – pedja

+1

+1 per indicare gli EFFETTI COLLATERALI – exexzian

4

In caso di dubbio, test. Usa un profiler. Misurare.

+0

La scrittura del microbenchmark è così difficile che sconsiglio sempre. A meno che non siate pronti a controllare l'assemblatore generato e sapere come la JVM ottimizza è un compito difficile – bestsss

4

Supponendo che l'ordine di iterazione non è rilevante, e anche supponendo che si vuole veramente nano-ottimizzare il codice, si può fare questo:

for (int i=someMethod(); i-->0;) { 
    //some code 
} 

Ma una variabile locale supplementare (il vostro a) non è disponibile un tale onere. In pratica, questo non è molto diverso dalla tua seconda versione.

+2

Siete nano-ottimizzati a scapito della leggibilità ... senza prove che la versione ottimizzata più leggibile (ovvia) non sarà solo veloce come. –

+0

Hum ... Non penso sia meno leggibile, almeno nel codice che mostro. Il lato negativo a mio parere è che i lettori e i manutentori di solito si aspettano che io stia crescendo, specialmente quando si sta ripetendo un elenco. –

+0

@dstroy - guarda la mia risposta per capire cosa sto dicendo. –

2

Dipende molto da quanto tempo occorre per generare l'output di someMethod(). Anche l'utilizzo della memoria sarebbe lo stesso, poiché someMethod() deve prima generare l'output e memorizzarlo. Il secondo modo protegge la CPU dal calcolo dello stesso output su ogni loop e non dovrebbe richiedere più memoria. Quindi il secondo è migliore.

2

Non considererei il consumo di memoria della variabile a come un problema in quanto è un int e richiede 192 bit su una macchina a 64 bit. Quindi preferirei la seconda alternativa in quanto l'efficienza di esecuzione è migliore.

3

Se non avete bisogno di questa variabile dopo ciclo, non v'è modo semplice per nasconderlo dentro:

for (int count = someMethod(), i = 0; i < count; i++) 
{ 
    // some code 
} 
0

Se è necessario ottimizzare questo, allora questo è il modo pulito/ovvio per farlo:

int a = someMethod(); 
for (int i = 0; i < a; i++) { 
    //some code 
} 

La versione alternativa suggerita da @dystroy

for (int i=someMethod(); i-->0;) { 
    //some code 
} 

... ha tre problemi.

  • Sta iterando nella direzione opposta.

  • L'iterazione non è unidirezionale e quindi è meno leggibile. Soprattutto se si ignora la guida allo stile Java e non si mettono gli spazi bianchi dove si suppone.

  • Non c'è alcuna prova che il codice sia effettivamente più veloce della versione più idiomatica ... specialmente una volta che il compilatore JIT li ha ottimizzati entrambi. (E anche se la versione meno leggibile è più veloce, la differenza è probabile che sia trascurabile.)

D'altra parte, se someMethod() è costoso (come postulato) poi "sollevamento" la chiamata in modo che è fatto solo una volta è probabile che valga la pena.

+0

la 1a variante [invocando nel ciclo] deve avere abbastanza 'budget in linea' da lasciare in linea someMethod(), esp. se può essere ignorato. Nessuna inlining significa più chiamate e non srotolamento del loop + possibili controlli di intervallo. – bestsss

1

La parte più importante dell'ottimizzazione del ciclo è consentire alla JVM di srotolare il ciclo. Per fare ciò nella prima variante deve essere in grado di inline la chiamata a someMethod(). Inlining ha un budget e può essere sballato a un certo punto. Se someMethod() è abbastanza lungo, la JVM può decidere che non gli piaccia essere in linea.

La seconda variante è più utile (al compilatore JIT) e probabilmente funzionerà meglio.

il mio modo per mettere giù il ciclo è: for (int i=0, max=someMethod(); i<max; i++){...}

max non inquina il codice, ci si assicura senza effetti collaterali da più chiamate di someMethod() ed è compatto (singolo liner)