Eu sou novo em java, e estava executando algum código ontem à noite, e isso realmente me incomodou. Eu estava construindo um programa simples para exibir todas as saídas X em um loop for, e notei uma enorme queda no desempenho quando usei o módulo como variable % variable
vs variable % 5000
ou outros enfeites. Alguém pode me explicar por que isso é e o que está causando isso? Para que eu possa ser melhor ...
Aqui está o código "eficiente" (desculpe se entendi um pouco de sintaxe, não estou no computador com o código no momento)
long startNum = 0;
long stopNum = 1000000000L;
for (long i = startNum; i <= stopNum; i++){
if (i % 50000 == 0) {
System.out.println(i);
}
}
Aqui está o "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);
}
}
Lembre-se de que eu tinha uma variável de data para medir as diferenças e, uma vez que ficou longa o suficiente, a primeira levou 50ms enquanto a outra levou 12 segundos ou algo assim. Você pode ter que aumentar stopNum
ou diminuir progressCheck
se o seu PC for mais eficiente que o meu ou não.
Procurei essa pergunta na Web, mas não consigo encontrar uma resposta, talvez não esteja fazendo a pergunta certa.
EDIT: Eu não esperava que minha pergunta fosse tão popular, agradeço todas as respostas. Realizei uma referência em cada metade do tempo gasto, e o código ineficiente demorou consideravelmente mais, 1/4 de segundo versus 10 segundos mais ou menos. É verdade que eles estão usando println, mas ambos estão fazendo a mesma quantidade, então eu não imaginaria que isso distorceria muito, especialmente porque a discrepância é repetível. Quanto às respostas, como sou novo em Java, deixarei os votos decidirem por enquanto qual é a melhor. Vou tentar escolher um até quarta-feira.
EDIT2: Vou fazer outro teste hoje à noite, onde, em vez de módulo, ele apenas incrementa uma variável e, quando atinge progressCheck, ele executa uma e, em seguida, redefine a variável para 0. para uma terceira opção.
EDIT3.5:
Eu usei esse código e abaixo mostrarei meus resultados .. Obrigado a todos pela maravilhosa ajuda! Eu também tentei comparar o valor curto do longo com 0, então todas as minhas novas verificações acontecem sempre "65536" vezes, tornando-o igual em repetições.
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:
- fixo = 874 ms (normalmente em torno de 1000ms, mas mais rápido devido a uma potência de 2)
- variável = 8590 ms
- variável final = 1944 ms (era ~ 1000ms ao usar 50000)
- incremento = 1904 ms
- Conversão curta = 679 ms
Não surpreende o suficiente, devido à falta de divisão, a conversão curta foi 23% mais rápida que a maneira "rápida". Isso é interessante notar. Se você precisar mostrar ou comparar algo a cada 256 vezes (ou por aí), faça isso e use
if ((byte)integer == 0) {'Perform progress check code here'}
UMA NOTA INTERESSANTE FINAL, o uso do módulo na "Variável declarada final" com 65536 (número não muito bonito) foi metade da velocidade (mais lenta) do que o valor fixo. Onde antes estava comparando com a mesma velocidade.
final
na frente daprogressCheck
variável, ambos correm na mesma velocidade novamente. Isso me leva a acreditar que o compilador ou o JIT consegue otimizar o loop quando sabe queprogressCheck
é constante.