Soy nuevo en Java, y estaba ejecutando algo de código anoche, y esto realmente me molestó. Estaba creando un programa simple para mostrar cada X salidas en un bucle for, y noté una disminución MASIVA en el rendimiento, cuando usé el módulo como variable % variable
vs variable % 5000
o no. ¿Puede alguien explicarme por qué es esto y qué lo está causando? Entonces puedo ser mejor ...
Aquí está el código "eficiente" (perdón si tengo un poco de sintaxis incorrecta, no estoy en la computadora con el código en este momento)
long startNum = 0;
long stopNum = 1000000000L;
for (long i = startNum; i <= stopNum; i++){
if (i % 50000 == 0) {
System.out.println(i);
}
}
Aquí está el "código ineficiente"
long startNum = 0;
long stopNum = 1000000000L;
long progressCheck = 50000;
for (long i = startNum; i <= stopNum; i++){
if (i % progressCheck == 0) {
System.out.println(i);
}
}
Eso sí, tenía una variable de fecha para medir las diferencias, y una vez que se hizo lo suficientemente larga, la primera tardó 50 ms, mientras que la otra tardó 12 segundos o algo así. Es posible que tenga que aumentar stopNum
o disminuir progressCheck
si su PC es más eficiente que la mía o no.
Busqué esta pregunta en la web, pero no puedo encontrar una respuesta, tal vez simplemente no la estoy preguntando correctamente.
EDITAR: No esperaba que mi pregunta fuera tan popular, agradezco todas las respuestas. Realicé un punto de referencia en cada mitad del tiempo empleado, y el código ineficiente tomó mucho más tiempo, 1/4 de segundo frente a 10 segundos más o menos. De acuerdo, están usando println, pero ambos están haciendo la misma cantidad, por lo que no me imagino que eso lo distorsione mucho, especialmente porque la discrepancia es repetible. En cuanto a las respuestas, dado que soy nuevo en Java, dejaré que los votos decidan por ahora qué respuesta es la mejor. Intentaré elegir uno para el miércoles.
EDIT2: Voy a hacer otra prueba esta noche, donde en lugar de módulo, solo incrementa una variable, y cuando alcanza el Progreso de comprobación, realizará una, y luego restablecerá esa variable a 0. para una tercera opción.
EDITAR 3.5:
Usé este código, y a continuación mostraré mis resultados. ¡Gracias a TODOS por la maravillosa ayuda! También intenté comparar el valor corto del largo con 0, por lo que todas mis nuevas comprobaciones suceden "65536" veces, haciéndolo igual en repeticiones.
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");
}
}
Resultados:
- fijo = 874 ms (normalmente alrededor de 1000 ms, pero más rápido debido a que es una potencia de 2)
- variable = 8590 ms
- variable final = 1944 ms (Fue ~ 1000ms cuando se usa 50000)
- incremento = 1904 ms
- Conversión corta = 679 ms
No es sorprendente, debido a la falta de división, la conversión corta fue un 23% más rápida que la forma "rápida". Esto es interesante de notar. Si necesita mostrar o comparar algo cada 256 veces (o más allá), puede hacer esto y usar
if ((byte)integer == 0) {'Perform progress check code here'}
UNA NOTA DE INTERÉS FINAL, el uso del módulo en la "Variable declarada final" con 65536 (no un número bonito) era la mitad de la velocidad (más lenta) que el valor fijo. Donde antes era benchmarking cerca de la misma velocidad.
final
delante de laprogressCheck
variable, ambos corren a la misma velocidad nuevamente. Eso me lleva a creer que el compilador o el JIT logra optimizar el ciclo cuando sabe queprogressCheck
es constante.