Какой из этих кусков кода быстрее в Java? - PullRequest
11 голосов
/ 01 ноября 2009

а) for(int i = 100000; i > 0; i--) {}

б) for(int i = 1; i < 100001; i++) {}

Ответ есть на этом сайте (вопрос 3). Я просто не могу понять почему? С сайта:

Ответы [ 16 ]

2 голосов
/ 01 ноября 2009

Это самый тупой вопрос, который я когда-либо видел. Тело цикла пустое. Если компилятор хорош, он просто не будет выдавать код вообще. Он ничего не делает, не может генерировать исключение и ничего не меняет за пределами своей области видимости.

Предполагая, что ваш компилятор не настолько умен, или что у вас фактически не было пустого тела цикла: Аргумент «обратный счетчик циклов» имеет смысл для некоторых языков ассемблера (это может иметь смысл и для байтового кода Java, я не знаю его конкретно). Тем не менее, компилятор очень часто будет иметь возможность преобразовать ваш цикл, чтобы использовать уменьшающиеся счетчики. Если у вас нет тела цикла, в котором значение i явно используется, компилятор может выполнить это преобразование. Итак, опять же, вы часто не видите никакой разницы.

2 голосов
/ 01 ноября 2009

Что касается проверки на ноль в JVM: очевидно, это можно сделать с помощью ifeq , тогда как для проверки чего-либо еще требуется if_icmpeq , что также включает в себя добавление дополнительного значения в стек.

Проверка на > 0, как и в вопросе, может быть выполнена с ifgt , тогда как для проверки на < 100001 потребуется if_icmplt .

1 голос
/ 01 ноября 2009

Петли идентичны, за исключением одной критической части:

i> 0; а также я <100001; </p>

Проверка больше нуля выполняется путем проверки бита NZP (обычно называемого кодом состояния или отрицательным нулем или положительным битом) компьютера.

Бит NZP устанавливается всякий раз, когда выполняются такие операции, как загрузка, AND и т.д. выполняются.

Проверка «больше чем» не может напрямую использовать этот бит (и, следовательно, занимает немного больше времени). Общее решение состоит в том, чтобы сделать одно из значений отрицательным (выполнив битовое НЕ, а затем добавив 1), а затем добавив его в сравниваемое значение. Если результат равен нулю, то они равны. Положительное, тогда второе значение (не отрицательное) больше. Отрицательное, тогда первое значение (отрицательное) больше. Эта проверка занимает немного больше времени, чем прямая проверка nzp.

Я не уверен на 100%, что это является причиной этого, но это кажется возможной причиной ...

0 голосов
/ 10 декабря 2015

Я проводил тесты уже около 15 минут, и на всякий случай ничего не происходило, кроме затмения, и я увидел реальную разницу, вы можете попробовать это.

Когда я попытался определить, сколько времени займет Java, чтобы сделать «ничего», мне потребовалось около 500 наносекунд, чтобы получить идею.

Затем я проверил, сколько времени потребуется для выполнения оператора for, где он увеличивается:

for(i=0;i<100;i++){}

Затем пять минут спустя я попробовал «задом наперед»:

for(i=100;i>0;i--)

И у меня есть огромная разница (в крошечном крошечном уровне) 16% между первым и вторым for утверждениями, причем последнее на 16% быстрее.

Среднее время выполнения «возрастающего» оператора for во время 2000 тестов: 1838 н / с

Среднее время выполнения «уменьшающегося» оператора for во время 2000 тестов: 1555 н / с

Код, используемый для таких испытаний:

public static void main(String[] args) {
    long time = 0;  
    for(int j=0; j<100; j++){
    long startTime = System.nanoTime();
    int i;
        /*for(i=0;i<100;i++){

        }*/
        for(i=100;i>0;i--){

        }
    long endTime = System.nanoTime();
    time += ((endTime-startTime));
    }
    time = time/100;
    System.out.print("Time: "+time);
}

Вывод: Разница, по сути, ничтожна, уже требуется значительное количество «ничего», чтобы «ничего не делать» по отношению к тестам операторов for, что делает разницу между ними незначительной, просто время, затрачиваемое на импорт библиотеки, такой как java.util.Scanner требует гораздо больше загрузки, чем выполнение оператора for, это не приведет к значительному повышению производительности вашего приложения, но все же это действительно здорово знать.

0 голосов
/ 01 ноября 2009

Суть в том, что для любого не критичного к производительности приложения разница, вероятно, не имеет значения. Как уже отмечали другие, бывают случаи, когда использование ++ i вместо i ++ может быть быстрее, однако, особенно в циклах for, любой современный компилятор должен оптимизировать это различие.

Тем не менее, разница, вероятно, связана с базовыми инструкциями, которые генерируются для сравнения. Тестирование, если значение равно 0, это просто NAND NOR gate. Принимая во внимание, что проверка того, что значение равно произвольной константе, требует загрузки этой константы в регистр, а затем сравнения двух регистров. (Это, вероятно, потребует дополнительной задержки на входе или двух.) Тем не менее, с конвейерной обработкой и современными ALU, я бы удивился, если бы различие было значительным для начала.

0 голосов
/ 01 ноября 2009

Ответ (как вы, вероятно, узнали на сайте)

Я думаю, причина в том, что условие i > 0 для завершения цикла быстрее тестируется.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...