Sono nuovo di Java e stavo eseguendo un codice la scorsa notte, e questo mi ha davvero infastidito. Stavo costruendo un semplice programma per visualizzare tutte le uscite X in un ciclo for, e ho notato una MASSIMA riduzione delle prestazioni, quando ho usato il modulo come variable % variable
vs variable % 5000
o whatnot. Qualcuno può spiegarmi perché questo è e cosa lo sta causando? Quindi posso essere migliore ...
Ecco il codice "efficiente" (scusate se ho un po 'di sintassi sbagliata, non sono sul computer con il codice in questo momento)
long startNum = 0;
long stopNum = 1000000000L;
for (long i = startNum; i <= stopNum; i++){
if (i % 50000 == 0) {
System.out.println(i);
}
}
Ecco il "codice inefficiente"
long startNum = 0;
long stopNum = 1000000000L;
long progressCheck = 50000;
for (long i = startNum; i <= stopNum; i++){
if (i % progressCheck == 0) {
System.out.println(i);
}
}
Intendiamoci, avevo una variabile di data per misurare le differenze, e una volta che è diventato abbastanza lungo, il primo ha impiegato 50ms mentre l'altro ha impiegato 12 secondi o qualcosa del genere. Potrebbe essere necessario aumentare stopNum
o diminuire il valore progressCheck
se il tuo PC è più efficiente del mio o no.
Ho cercato questa domanda sul Web, ma non riesco a trovare una risposta, forse non la sto facendo nel modo giusto.
EDIT: Non mi aspettavo che la mia domanda fosse così popolare, apprezzo tutte le risposte. Ho eseguito un benchmark su ogni metà del tempo impiegato e il codice inefficiente ha richiesto molto più tempo, 1/4 di secondo contro 10 secondi di dare o avere. Certo, stanno usando println, ma entrambi stanno facendo lo stesso importo, quindi non immaginerei che ciò possa distorcere molto, soprattutto perché la discrepanza è ripetibile. Per quanto riguarda le risposte, dato che sono nuovo di Java, permetterò ai voti di decidere per ora quale sia la risposta migliore. Proverò a sceglierne uno entro mercoledì.
EDIT2: Stasera farò un altro test, dove invece del modulo, incrementa semplicemente una variabile e quando raggiunge progressCheck ne eseguirà una, quindi resetterà quella variabile a 0. per una terza opzione.
EDIT3.5:
Ho usato questo codice e di seguito mostrerò i miei risultati .. Grazie a tutti per il meraviglioso aiuto! Ho anche provato a confrontare il valore breve del long con 0, quindi tutti i miei nuovi controlli si verificano sempre "65536" volte rendendolo uguale nelle ripetizioni.
public class Main {
public static void main(String[] args) {
long startNum = 0;
long stopNum = 1000000000L;
long progressCheck = 65536;
final long finalProgressCheck = 50000;
long date;
// using a fixed value
date = System.currentTimeMillis();
for (long i = startNum; i <= stopNum; i++) {
if (i % 65536 == 0) {
System.out.println(i);
}
}
long final1 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
//using a variable
for (long i = startNum; i <= stopNum; i++) {
if (i % progressCheck == 0) {
System.out.println(i);
}
}
long final2 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
// using a final declared variable
for (long i = startNum; i <= stopNum; i++) {
if (i % finalProgressCheck == 0) {
System.out.println(i);
}
}
long final3 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
// using increments to determine progressCheck
int increment = 0;
for (long i = startNum; i <= stopNum; i++) {
if (increment == 65536) {
System.out.println(i);
increment = 0;
}
increment++;
}
//using a short conversion
long final4 = System.currentTimeMillis() - date;
date = System.currentTimeMillis();
for (long i = startNum; i <= stopNum; i++) {
if ((short)i == 0) {
System.out.println(i);
}
}
long final5 = System.currentTimeMillis() - date;
System.out.println(
"\nfixed = " + final1 + " ms " + "\nvariable = " + final2 + " ms " + "\nfinal variable = " + final3 + " ms " + "\nincrement = " + final4 + " ms" + "\nShort Conversion = " + final5 + " ms");
}
}
risultati:
- fisso = 874 ms (normalmente intorno a 1000ms, ma più veloce perché è una potenza di 2)
- variabile = 8590 ms
- variabile finale = 1944 ms (era ~ 1000ms quando si utilizza 50000)
- incremento = 1904 ms
- Conversione breve = 679 ms
Non abbastanza sorprendente, a causa della mancanza di divisione, la conversione corta è stata del 23% più veloce del modo "veloce". Questo è interessante da notare. Se devi mostrare o confrontare qualcosa ogni 256 volte (o lì), puoi farlo e utilizzare
if ((byte)integer == 0) {'Perform progress check code here'}
UNA NOTA DI INTERESSE FINALE, usando il modulo sulla "Variabile dichiarata finale" con 65536 (non un bel numero) era la metà della velocità (più lenta) del valore fisso. Dove prima era benchmarking alla stessa velocità.
final
davanti allaprogressCheck
variabile, corro di nuovo entrambi alla stessa velocità. Questo mi porta a credere che il compilatore o la JIT riescano a ottimizzare il loop quando sa cheprogressCheck
è costante.