Я новачок в Java, і вчора ввечері працював якийсь код, і це мене дуже турбувало. Я будував просту програму для відображення всіх результатів X у циклі for, і я помітив МАСИВНЕ зниження продуктивності, коли я використовував модуль як variable % variable
vs variable % 5000
чи що. Чи може хтось мені пояснити, чому це так і що це викликає? Так що я можу бути кращим ...
Ось "ефективний" код (вибачте, якщо я неправильно позначив синтаксис, я зараз не на комп'ютері з кодом)
long startNum = 0;
long stopNum = 1000000000L;
for (long i = startNum; i <= stopNum; i++){
if (i % 50000 == 0) {
System.out.println(i);
}
}
Ось "неефективний код"
long startNum = 0;
long stopNum = 1000000000L;
long progressCheck = 50000;
for (long i = startNum; i <= stopNum; i++){
if (i % progressCheck == 0) {
System.out.println(i);
}
}
Зауважте, у мене була змінна дата для вимірювання різниць, і як тільки вона стала достатньо довгою, перша займала 50 мс, а друга займала 12 секунд чи щось подібне. Можливо, вам доведеться збільшити stopNum
або зменшити, progressCheck
якщо ваш ПК більш ефективний, ніж мій, чи ні.
Я шукав це питання в Інтернеті, але не можу знайти відповідь, можливо, я просто не ставлю його правильно.
EDIT: Я не очікував, що моє запитання буде таким популярним, я ціную всі відповіді. Я виконував орієнтир на кожну половину зайнятий час, і неефективний код зайняв значно більше часу, 1/4 секунди проти 10 секунд дають або беруть. Зрозуміло, вони використовують println, але вони обидва роблять однакову суму, тому я не думаю, що це перекосило б це сильно, тим більше, що розбіжність повторюється. Що стосується відповідей, так як я новачок у Java, я зараз дозволю голосам вирішити, яка відповідь найкраща. Я спробую вибрати один до середи.
EDIT2: Я збираюся зробити ще один тест сьогодні ввечері, де замість модуля він просто збільшує змінну, і коли вона досягне progressCheck, вона виконає одну, а потім скине цю змінну до 0. для 3-го варіанту.
EDIT3.5:
Я використовував цей код, і нижче я покажу свої результати .. Дякую ВСІМ за чудову допомогу! Я також спробував порівняти коротке значення long з 0, тому всі мої нові перевірки трапляються колись "65536" разів, роблячи це рівним у повторах.
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");
}
}
Результати:
- фіксовано = 874 мс (як правило, близько 1000 мс, але швидше завдяки потужності 2)
- змінна = 8590 мс
- остаточна змінна = 1944 мс (було ~ 1000 мс при використанні 50000)
- приріст = 1904 мс
- Коротке перетворення = 679 мс
Не дивно, що через відсутність поділу Коротка конверсія була на 23% швидшою, ніж "швидкий" шлях. Це цікаво зазначити. Якщо вам потрібно показувати або порівнювати щось кожні 256 разів (або приблизно там), ви можете це зробити і використовувати
if ((byte)integer == 0) {'Perform progress check code here'}
ОДНА ЗАКЛЮЧНА ПРИМІТКА, використання модуля на "Остаточній оголошеній змінній" з 65536 (не досить число) було вдвічі швидше (повільніше), ніж фіксоване значення. Де раніше це було тестування майже з однаковою швидкістю.
final
передprogressCheck
змінною, обидва знову бігаються з однаковою швидкістю. Це приводить мене до думки, що компілятор або JIT вдається оптимізувати цикл, коли він знає, щоprogressCheck
це постійне.