Эффективность вложенного цикла

посмотреть следующий фрагмент:

    Long first_begin = System.currentTimeMillis();

    // first nested loops
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 1000000; j++) {
            // do some stuff
        }
    }
    System.out.println(System.currentTimeMillis() - first_begin);
    // second nested loops
    Long seconde_begin = System.currentTimeMillis();
    for (int i = 0; i < 1000000; i++) {
        for (int j = 0; j < 10; j++) {
            // do some stuff
        }
    }
    System.out.println(System.currentTimeMillis() - seconde_begin);

Мне интересно, почему первые вложенные циклы работают медленнее, чем второй?

С уважением!

Важное Примечание!: мне жаль, что я сделал переменную j, начинающуюся с 1 случайно, когда этот вопрос впервые задан, я сделал исправление.

Update:в циклах нет никакой конкретной логики, я просто делаю какой-то тест, на самом деле это вопрос, заданный во время интервью и интервьюер намекают мне изменить порядок циклов для достижения лучшей производительности. Кстати, я использую JDK1.5. после некоторого теста я теперь более смущен, потому что результат программы не согласован-когда-то первый цикл работает быстрее, чем второй, но большую часть времени он работает медленнее, чем второй.

4 ответов


этот ответ для обновленного вопроса:

  • если вы получаете доступ к двумерному массиву, например int[][], тот, у которого большее значение во внутреннем цикле должно быть медленнее. Не намного, но все же. Чтобы несколько понять проблему, прочитайте о уличный художник Шлемиэль в одном из блогов Джоэла.
  • причина вы получаете противоречивые результаты, что вы не выполняя любую JVM прогрева. JVM постоянно анализирует байт-код, который запускается и оптимизирует его, обычно только после 30 до 50 итераций он работает с оптимальной скоростью. Да, это означает, что вам нужно запустить код сначала пару десятков раз, а затем проверить его в среднем еще пару десятков запусков из-за сборщика мусора, который замедлит пару запусков.
  • общее Примечание, используя Long объект вместо long примитив просто тупой, JVM, скорее всего, оптимизирует его, заменив его примитивным, если он может, а если нет, то обязательно некоторые (хотя и крайне незначительные) постоянное замедление от его использования.

EDIT: оригинальный ответ ниже. Теперь, когда вы исправили пример так, что все переменные цикла начинаются с 0, мы возвращаемся к просто недостаточной информации. Кажется скорее что это проблема когерентности / локальности кэша ссылки, но мы просто догадываемся. Если бы вы могли предоставить короткую, но полную программу, которая демонстрирует проблему, что бы помочь... как бы сказать нам, с какого языка / платформы мы говорим о начале!


в первый цикл 10 * 999999 = 9999990 итераций. Второй цикл имеет 1000000 * 9 = 9000000 итераций. Поэтому я бы ... --1-->ожидал (при прочих равных условиях) первый цикл занимает больше времени.

, вы не указали, какую работу вы делаете и на какой платформе это. Есть много вещей, которые могут повлиять на вещи:
  • второй цикл может поразить кэш лучше
  • если вы используете JIT-скомпилированную платформу, JIT может иметь выбран для оптимизации второго цикла более интенсивно.
  • операции, которые вы выполняете, могут сами иметь кэширование или что-то в этом роде
  • если вы выполняете небольшой объем работы, но сначала нужно загрузить и инициализировать кучу типов, это может привести к тому, что первый цикл будет медленнее

Если вы посмотрите на сгенерированный байтовый код, два цикла почти идентичны. За исключением того, что когда он делает условие while для цикла 10, Java получает 10 как немедленное значение из инструкции, но когда он делает условие while для цикла 1000000, Java загружает 1000000 из переменной. У меня нет информации о том, сколько времени требуется для выполнения каждой инструкции, но кажется вероятным, что немедленная загрузка будет быстрее, чем загрузка из переменной.

Примечание., затем, что в первом цикле сравнение с 1000000 должно быть сделано 10 миллионов раз, в то время как во втором цикле это делается только 1 миллион раз. Конечно, сравнение с 10 выполняется гораздо чаще во втором цикле, но если переменная нагрузка намного медленнее, чем непосредственная нагрузка, это объясняет результаты, которые вы видите.


вопрос сместился. Это не те дроиды, которых вы ищете...

потому что вы делаете ~1000000 раз больше работы в первом примере. ;-)