Подтвердить что ты не робот

Groovy для времени выполнения цикла

O Groovy Гуру,

Этот фрагмент кода работает примерно за 1 секунду

    for (int i in (1..10000000)) {
         j = i;
    }

в то время как этот занимает почти 9 секунд

    for (int i = 1; i < 10000000; i++) {
         j = i;
    }

Почему так?

4b9b3361

Ответ 1

Ok. Вот мой вопрос: почему?

Если вы конвертируете оба скрипта в байт-код, вы заметите, что

  • ForInLoop использует Range. Итератор используется для продвижения во время каждого цикла. Сравнение (<) производится непосредственно с int (или Integer), чтобы определить, было ли выполнено условие выхода или нет.
  • ForLoop использует традиционный прирост, проверяет состояние и выполняет действие. Для проверки условия я < 10000000 использует Groovy ScriptBytecodeAdapter.compareLessThan. Если вы углубитесь в этот код метода, вы обнаружите, что обе стороны сравнения берутся как Объект, и происходит так много вещей, кастинг, сравнение их как объекта и т.д.

ScriptBytecodeAdapter.compareLessThan → ScriptBytecodeAdapter.compareTo → DefaultTypeTransformation.compareTo

Существуют другие классы в пакете обработки типов, который реализует метод compareTo специально для математических типов данных, не уверен, почему они не используются (если они не используются)

Я подозреваю, что причина в том, что вторая петля занимает больше времени. Опять же, пожалуйста, поправьте меня, если я ошибаюсь или что-то не хватает...

Ответ 2

В своем тестировании, прежде чем принимать меры, обязательно "согреть" JVM, иначе вы можете запустить различные действия по запуску на платформе (загрузка классов, компиляция JIT). Выполняйте тесты много раз подряд. Кроме того, если вы сделали второй тест, пока собирался сбор мусора, это может повлиять. Попробуйте запустить каждый из тестов 100 раз и распечатать время после каждого теста и посмотреть, что это говорит вам.

Ответ 3

Если вы можете устранить потенциальные артефакты из времени запуска, как предлагает Джим, тогда я бы поставил под сомнение, что цикл Java для цикла в Groovy не так хорошо реализован, как исходный стиль Groovy для цикла. Он был добавлен только с версии 1.5 после запросов пользователя, поэтому, возможно, его реализация была немного запоздалой.

Вы взглянули на байт-код, сгенерированный для ваших двух примеров, чтобы увидеть, есть ли какие-либо различия? Здесь обсуждалась Groovy производительность здесь, в которой один из комментариев (из одной "johnchase" ) говорит следующее:

Интересно, относится ли разница, связанная с тем, как Groovy использует числа (примитивы) - поскольку она обертывает все примитивы в своих эквивалентных классах оболочки Java (int → Integer), Id предсказывает, что это немного замедлит работу, Я заинтересован в том, чтобы производительность Java-кода составляла 10 000 000, используя классы-оболочки вместо int.

Итак, возможно, исходный цикл Groovy for не страдает от этого? Просто размышления с моей стороны действительно.