Я написал две части кода, почти одинаковые, но одна работает намного быстрее, чем другая (Java) - PullRequest
0 голосов
/ 11 апреля 2020

Я запустил этот сегмент кода: (внешний l oop выполняется 100 раз, внутренний l oop выполняется 1 миллиард раз.)

long l = 0;

for(int i = 0; i < 100; i++)
    for(int j = 0; j < 1000000000; j++)
        l++;

System.out.println(l);

Это заняло около 11-12 секунд, когда я побежал it.

Затем я запустил этот сегмент кода:

long l = 0;
int i = 0, j = 0;

for(; i < 100; i++)
    for(; j < 1000000000; j++)
        l++;

System.out.println(l);

, и это занимало около 100 мс (0,1 секунды) каждый раз, когда я запускал его.

У кого-нибудь есть идея, почему есть большая разница? Моя теория состоит в том, что для каждого значения 'i' внутреннее значение для l oop должно снова инициализировать j, что дает ему больше операций, поэтому имеет смысл, что это занимает больше времени. Тем не менее, разница огромна (примерно в 100 раз), и с другими подобными тестами то же самое не происходит.

Если вы хотите увидеть это сами, я рассчитал это так:

class Main {
    static long start, end;
    public static void main(String[] args) {
        start();

        long l = 0;
        int i = 0, j = 0;

        for(; i < 100; i++)
            for(; j < 1000000000; j++)
                l++;

        System.out.println(l);

        end();
        print();
    }

    public static void start() {
        start = System.currentTimeMillis();
    }

    public static void end() {
        end = System.currentTimeMillis();
    }

    public static void print() {
        System.out.println((end -  start) + " ms.");
    }
}

Ответы [ 5 ]

4 голосов
/ 11 апреля 2020

Вторая функция выполняет итерацию только через j для первой итерации I. В этой точке j превышает предел для l oop и никогда не запускается снова, поскольку она не сбрасывается на следующей итерации i

1 голос
/ 11 апреля 2020

Реальная причина - во втором случае l oop не работает так же, как первый код.

В первом коде каждый раз, когда вы go внутри запускаете j. С 0 Но во втором коде j будет 1 миллиард в первой итерации. После этого всегда будет 1billoin. Это означает, что второе условие l oop каждый раз терпит неудачу. Второй l oop не будет запускаться более одного раза.

1 голос
/ 11 апреля 2020

В вашем первом примере внутренний l oop работает от 0 до 1000000000 для каждого значения i, потому что мы инициализируем j = 0 для каждого значения i.
Во втором примере, внутренний l oop выполняется от 0 до 1000000000 только для i = 0, потому что здесь мы инициализируем j = 0 только для первой итерации внешнего l oop (т.е. i = 0).

0 голосов
/ 06 мая 2020

j установлен на 0 вне его для l oop. Он никогда не будет сброшен до 0 на следующей итерации.

0 голосов
/ 11 апреля 2020

Две версии не "почти одинаковы". На самом деле они совершенно разные.

Подсказка в том, что они печатают разные значения для l:

/tmp$ java Main1.java
1000000000
12 ms.

/tmp$ java Main2.java
100000000000
857 ms.

Очевидно, что одна версия выполняет в 100 раз больше итераций, чем другая. @ Ответ Оли объясняет почему.


Моя теория состоит в том, что для каждого значения i внутреннее значение для l oop должно снова инициализировать j , что дает ему больше операций, поэтому имеет смысл, что это займет больше времени.

Нет. Это не объясняет разницу в производительности в 100 раз. не правдоподобно , что 100 инициализаций переменной int заняли бы (на моей машине) 800+ миллисекунд.

Реальное объяснение состоит в том, что вы сравниваете вычисления, которые НЕ сравнимы.

...