Newsgroup: it.comp.java
Titolo: consuma più cpu un if o un'eccezione ?

Ciao a tutti,
devo ottimizzare un loop e mi trovo a dover gestire un errore che potrei 
evitare con un "if (a<b) {}" ad ogni ciclo.
Mi chiedevo se l'esecuzione sarà più veloce testando l'if oppure facendo 
lanciare l'eccezione e gestendola nel catch.
Che ne pensate?
Grazie
Bye!
-- 
elimina unsampdoriano per rispondere via email

 Che ne pensate?
Mai ottimizzare prima di aver dimostrato (con misure) che è necessario 
ottimizzare.
Mai (o quasi) prediligere un ottimizzazione della velocità a scapito 
della leggibilità, soprattutto se non hai ancora dimostrato che 
l'ottimizzazione è necessaria.
Mai ottimizzare senza aver dimostrato o poter dimostrare che le 
modifiche effettivamente fanno girare il programma piu' veloce.
Mai ottimizzare senza aver individuato in modo scientifico (con un 
profiler per esempio, ma anche con altre misure) il punto dove il 
programma perde piu' tempo.
Il tuo programma è lento? Un approccio di dettaglio non lo farà 
diventare piu' veloce. Devi usare un approccio a livello architetturale 
o algoritmico per farlo.
Facci vedere questo loop. Da chi viene chiamato? Quante volte? Quanto 
dura il loop? Sei sicuro che è questo loop la causa dei problemi?
-- 
Andrea Francia
http://www.andreafrancia.it/

 
in realtà non è che sia proprio un problema. Sto sviluppando un gioco 
j2me e vorrei farlo andare il più fluido e veloce possibile.
Siccome ad ogni loop devo fare diversi check di collisione su varie 
coordinate, penso che risparmiare qualche millisecondo dove possibile 
non possa che essere d'aiuto.



Il miei consigli sono questi:
  - leggiti i consigli sullo sviluppo di giochi su j2me (non li ho mai 
visti ma sono sicuro che qualcuno li abbia scritti).
    Da quel poco che so, di solito, il grosso del calcolo è dovuto alla 
gestione della grafica piuttosto che dal controllo delle collisioni.
    La fluidità credo che si ottenga con tecniche di double buffering, 
ma ti conviene riferirti all'ipotetico documento di consigli per i 
giochi su j2me piuttosto che basarti sulle mie scarse conoscenze di 
video giochi.
  - concentrati sul fare un programma manutenibile e che funziona, poi 
quando, e se, vedi che è troppo lento occupati del problema 
ottimizzazione. Ottimizzare un programma manutenibile è più semplice che 
manutenere un programma "ottimizzato".


Generale Cluster ha scritto:

penso che l'eccezione sia pià onerosa essendo che necessità di una 
interruzione software (detta "trap")
-----------------------------------------------
Inviato tramite 
http://itwebnewsreader.servehttp.com

Generale Cluster ha scritto:
[cut]
 >--
 >elimina unsampdoriano per rispondere via email
Impossibile per me. Ho provato a cercarne uno dalle mie parti, introvabile.
--
ac

 lanciare l'eccezione e gestendola nel catch.
Certamente peggio usare un'eccezione:
- viene creata un'istanza di XXXXException: spreco di memoria, ma non
troppo costoso, in fondo;
- viene eseguito del codice per creare questa istanza: spreco di cicli
di CPU;
- deve essere costruito uno stack trace: e qui si buttano via pacchi e
pacchi di CPU e memoria...
Ergo, se ha senso, se il codice rimane leggibile (vero Francia?), se
non introduce dei problemi, vai pure tranquillo di if :)
--
www.megadix.it

Mai ottimizzare senza aver individuato[...]
E sopratutto mai "ottimizzare" un if con un'eccezione :-)

lanciare l'eccezione e gestendola nel catch.
Il problema è di fondo: le eccezioni non si usano per questo. Non è
una ragione di efficienza o meno (e ti assicuro che la gestione delle
eccezioni è *decisamente* onerosa), il punto è che i controlli logici
non vanno sostituiti da eccezioni. L'uso delle eccezioni deve essere
ben inquadrato e ben limitato. Nel caso specifico massacreresti le
performance sostituendo un if con un'eccezione, ma vorrei che tu
comprendessi che il problema è a monte: le eccezioni vanno usate per
gestire ciò che sono appunto "eccezioni", NON per testare - ad esempio
- se il divisore di un dividendo è zero (ti assicuro che ho visto
codice del genere). 

Andrea Laforgia ha scritto:

anche in alcuni posti dove ho lavorato le usano/usavano per scopi simili.
Io invece farei il percorso inverso, cioè metterei un if per evitare 
l'eccezione, a condizione che l'if non sia peggiorativo in termini di 
performance.




Un if non è mai peggiorativo in termini di performance. Immagino che
tu sappia che un if, in fin dei conti, si tramuta direttamente in
un'istruzione di confronto o di salto condizionato, mentre gestire
un'eccezione implica l'aggiunta di un'intera infrastruttura al codice,
peggiorando le cose e in termini di spazio, e in termini di tempo.
Tieni presente che in alcuni linguaggi esiste ancora il "goto", chiuso
a chiave in una scatola con su scritto "da usare solo in caso di
guerra nucleare". In alcuni spezzoni di codice il goto è utile per
venir fuori in maniera rapida da codice molto innestato, ma ormai i
vantaggi prestazionali di questa tecnica sono assolutamente
trascurabili. In C fino a non molto tempo fa si usavano setjmp/longjmp
per realizzare qualcosa di molto simile alle eccezioni.
Non sono d'accordo sulla tecnica dell'if PER EVITARE un'eccezione. Le
eccezioni vanno usate, con criterio, ma vanno usate. E comunque ci
sono diverse scuole di pensiero. Per esempio ci sono coloro che
sostengono fortemente il modello EAFP ("it's easier to ask forgiveness
than permission") tirato fuori da Grace Hopper (l'inventrice del
COBOL) e che sostanzialmente non si preoccupa dei test a monte. Di
contro c'è il modello LBYL ("look before you leap" aka LBYL), che
invece è proprio quello a cui tu fai riferimento.


Se ci fai vedere il codice ti possiamo dare dei consigli piu' centrati.
-- 
Andrea Francia
http://andreafrancia.blogspot.com/2008/07/colinux-linux-dentro-windows.html

 
Tipo hai un codice fatto cosi ?
while(cond) {
	<codice che se a>=b viene lanciata una eccezione>	
}
e trasformarlo in:
while(cond) {
	if (a >= b) continue;
	<codice che se a>=b viene lanciata una eccezione>	
}
Domanda che ti devi chiedere (efficienza a parte):
è giusto escludere  <codice che se a>=b viene lanciata una eccezione>
se a >=b oppure è un caso che se si verifica , e naturalmente in 
condizione normali non si verifica, deve venire eseguita una eccezione ?
Spero di essermi spiegato

 se non introduce dei problemi, vai pure tranquillo di if :)
Spesso e' volentieri non solo un if e' piu' efficiente, ma e' anche la 
soluzione migliore. Le "exceptions" dovrebbero essere usate solo in 
situazioni "exceptional", non dovrebbero essere usate per emulare un if.
Tommy

enoquick ha scritto:

la situazione è come hai descritto, con le seguenti varianti:
- due for annidati al posto del while
- (i*K+j)%K == 0 && j!=0 al posto di a>=b
- al posto del continue potrebbe esserci un break
la mia perplessità riguarda soprattutto quanto possa pesare fare quel 
calcolo ad ogni loop, rispetto a lasciar correre un'eccezione una volta 
ogni 10 cicli.
L'eccezione è una arrayindexoutofbound e chiaramente non si deve verificare.


ogni 10 cicli.
"Lasciar correre un'eccezione una volta ogni 10 cicli" significa
trovarsi comunque, nel compilato del loop, delle istruzioni che
verificano se lanciare o meno l'eccezione. In alcuni linguaggi (come
il C) per esempio, non esiste range checking sugli array per motivi
prettamente di efficienza. In ogni caso, come già detto, il peso
prestazionale di un if è pressoché irrilevante.

 - (i*K+j)%K == 0 && j!=0 al posto di a>=b
ehm, non vorrei dire una puttanata ma:
(i*K)%K == 0 sempre.
quindi il tuo calcolo si semplifica in if(j%K==0 && j!=0), che ti risparmia 
un * e un +. Che se e' un loop eseguito molto spesso puo' fare la 
differenza (un po' almeno).
Quindi vero che bisogna mantenere il codice leggibile e tutto, ma evitare 
di far fare calcoli inutili al processore e' la base per avere programmi 
snelli, veloci e con meno errori.
Ciao Jack
-- 
Eroi non si nasce, ti incastrano
- Jim Belushi

 - Mostra testo citato -
Se non ho capito male, fai qualcosa di questo tipo:
Object[] x...
for(int i=0;i<x.length;i++){
  x[i]...
}
e l'istruzione i<x.length viene valutata x.length volte.
Se tu invece fai
Object[] x...
try{
for(int i=0; ;i++){
  x[i]...
}
catch(ArrayIndexOutOfBoundException e){}
ottieni funzionalmente la stessa cosa (o quasi, potresti catturare per
errore ArrayIndexOutOfBoundException di altri array..), ma non valuti
mai i<x.length.
Purtroppo la tua intuizione è vera, ovvero se l'array è molto grande,
il risparmio sulla valutazione di uscita dal for può essere maggiore
rispetto alla spesa di costruzione dell'ogg. eccezione (esperienza
personale). Dico purtroppo perché sono perfettamente d'accordo su
quanto detto dagli altri di questo thread rispetto all'ottimizzazione
precoce, e sul fatto che probabilmente ci sono punti più critici da
ottimizzare rispetto ad una if. Una sola nota per chi dice che l'IF è
una operazione praticamente istantanea: dipende! E' vero, ma non
trascurare il tempo di valutazione della condizione... se per esempio,
ho una if(aspettaIlTramDelleDieci()) potrebbe metterci una giornata ad
eseguirsi....
Cmq, i benchmark fatti da me danno esito favorevole alle eccezioni
solamente in casi di arrays veramente grossi... parliamo di 1M di
elementi o giù di li, e che cmq dipende molto dalla JVM e dal JIT
(quindi può essere completamente diverso il caso di una JRE J2ME!), e
non aspetterti grosse differenze cmq.

 personale).
Il problema è che in Java hai comunque e sempre range checking attivo e
quindi controllo costante sui limiti dell'array, sia nel caso di un loop
con condizione d'uscita che senza, quindi è effettivamente possibile che
non preoccupandosi di sforare, ma affidandosi all'eccezione sollevata dal
range checking le prestazioni alla lunga (lunghissima) migliorino. Io non
starei però a spaccare il capello delle prestazioni in Java, perché per un
millisecondo risparmiato ce n'è qualche centinaio perso da altre parti
(gestione differita delle risorse da parte di un gc, controlli interni
alla VM, ecc...). Inoltre, perché non si pensi che questa tecnica sia
valida comunque e sempre, ci tengo a dire che in altri linguaggi vale
l'esatto contrario: l'if è sempre più efficiente di una gestione delle
eccezioni, proprio perché potrebbe non esserci range checking attivo. Il
discorso sul tempo di calcolo dell'if che potrebbe richiedere mezza
giornata non ha molto senso perché, in quanto stiamo dicendo, si suppone
che la condizione testata dall'if e quella testata dal range checking sia
la stessa. Una singola istruzione if, tradotta in un "cmp" o un "jmp" più
o meno sofisticato è sempre più efficiente (in termini di spazio e tempo)
di un controllo più complesso.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 mai i<x.length.
se invece usi una variabile di appoggio la valuti UNA volta e non hai 
l'eccezione tra le balle.
Object[] x;
int x_length = x.length;
for(int i=0; i<x_length,i++){
    	//...
}
chiaro che le la lunghezza di x varia nel for non si puo' fare...



La dimensione degli array non puo' cambiare in Java (da specifica del 
linguaggio).
I cicli for su un array sono un idiona comune, credo il compilatore sia 
già fatto in modo di ottimizzare al meglio un tale ciclo senza che il 
programmatore ci metta le mani.
In piu' la modifica che fa intervenire la variabile x_length potrebbe 
intralciare l'eventuale ottimizzazione del compilatore perché mentre è 
x.length è final x_length non lo è.


 x.length è final x_length non lo è.
mmhh questo non penso.
probabilmente, se x_length viene usata solo li, il compilatore la lascia 
in un registro senza neanche assegnargli un indirizzo in RAM.


 in un registro senza neanche assegnargli un indirizzo in RAM.
Infatti ho scritto "potrebbe" ;)


 }
O ancora meglio:
for(Object o : x){
   // ...
}
Tommy


Ok, su quello che avede detto tutti in risposta al mio post, in
sostanza diciamo le stesse cose. MAI fare queste cose (parlo di usare
le ccezzioni per gestire la logica applicativa). Parlavo in senso
strettamente teorico, e sono sicuro al 100% che ci sono altre
miglioire che valga la pena di metterein piedi (soprattutto
algoritmiche)
la valutazione di cui parlavo, cmq, non è tanto il x.length, ma l'
i<x.length. Intendo, che per quanto ottimizzi, c'è sempre di mezzo
l'istruzione di '<' che porta via (pochi) cicli. Però, in un certo
senso, siccome java di suo la esegue internamente, come già detto da
Andrea Laforgia, è ridondante, e quindi potrebbe essere omesso usando
l'eccezione.
Il for(Object o : x){ è un 'lusso' sintattico, non fa risparmiare
istruzioni, solo peché non le vedi. Non che io sia contrario, io la
uso il 99% del tempo...

 uso il 99% del tempo...


 l'istruzione di '<' che porta via (pochi) cicli. Però, in un certo
1 ciclo (di solito).


Generale Cluster ha scritto:

OK, vediamo un po:
1)
while(cond1) {
      <istr>
      .....
     try {
     	while(cond2) {
             <istr>...
         }
     }
     catch(arrayindexoutofboundexception e) {}
     <istr>
     ....
}
contro
2)
while(cond1) {
      <istr>
      .....
    while(cond2)  {
             if (!indexcorretto()) break;
             <istr>...
     }
     <istr>
     ....
}
1) genera piu codice dovuto al try catch da gestire ed inoltre viene 
sempre generato un oggetto di tipo arrayindexoutofboundexception ad ogni 
loop (che occupa memoria fino a quando non interviene il gc)
2) ha solo l' overhead di  if (!indexcorretto()) break
Quand' è che 1) è piu efficiente di 2) ?
Solo nel caso che il loop interno esegua molti cicli (tanti cicli )
Quanti lo si puo stabilire attraverso il profiling del codice; ma se il 
tuo loop occupa un max di 10 o 20 cicli stai sicuro che 2) è migliore di 1).

 for(Object o : x){
tanto piu' che hai messo una "virgola" prima del i++ invece del "punto e 
virgola" a dimostrazione del fatto che piu' semplice e' la forma e meno 
facile e' sbagliare ;-)
Tommy

 letto.
Il concetto e' semplicemente il seguente... (non so i dati veri quandi sparo 
a caso giusto per darti una idea)...
supponi che l'exception (con stack trace) costi l'equivalente di 10,000,000 
di '<' allora se il ciclo ha piu' di 10 milioni di iterazioni conviene da un 
punto di vista prestazionale uscire con una exception. Ovviamente se fai 100 
iterazioni impiegi molto piu' tempo e non ha senso.
Questa e' la teoria, in pratica sono contrario ad ottimizzazioni di questo 
tipo.
Tommy

 facile e' sbagliare ;-)
gli errori di sintassi fortunatamente li becca il parser del
compilatore.
gli errori di concetto no. :)
Ciao Jack
-- 
Yoda of Borg am I! Assimilated shall you be! Futile resistance is, hmm?

 gli errori di concetto no. :)
Si chiaro, ma avresti potuto scrivere:
for(int i=0; i<x_length,i++){
    x[j].fun();
ed il compilatore non si sarebbe lamentato (sempre che esistano sia i che 
j).
Mentre con:
for(Type t : x){
   t.fun();
e' molto piu' difficile fare errori.
Tommy