Скорость итерации int против long - PullRequest
8 голосов
/ 09 апреля 2010

У меня есть две следующие программы:

long startTime = System.currentTimeMillis();
for (int i = 0; i < N; i++);
long endTime = System.currentTimeMillis();
System.out.println("Elapsed time: " + (endTime - startTime) + " msecs");

и

long startTime = System.currentTimeMillis();
for (long i = 0; i < N; i++);
long endTime = System.currentTimeMillis();
System.out.println("Elapsed time: " + (endTime - startTime) + " msecs");

Примечание: единственная разница - это тип переменной цикла (int и long).

Когда я запускаю это, первая программа последовательно печатает от 0 до 16 мсек, независимо от значения N. Вторая занимает намного больше времени. Для N == Integer.MAX_VALUE он работает на моей машине примерно за 1800 мсек. Время выполнения кажется более или менее линейным в N.

Так почему же это?

Полагаю, JIT-компилятор оптимизирует цикл int до смерти. И не зря, потому что, очевидно, это ничего не делает. Но почему это не так для цикла long?

Коллега подумал, что мы можем измерить JIT-компилятор, выполняя свою работу в цикле long, но, поскольку время выполнения кажется линейным в N, это, вероятно, не так.

Я использую JDK 1.6.0 обновление 17:

C:\>java -version
java version "1.6.0_17"
Java(TM) SE Runtime Environment (build 1.6.0_17-b04)
Java HotSpot(TM) 64-Bit Server VM (build 14.3-b01, mixed mode)

Я работаю на Windows XP Professional x64 Edition, с пакетом обновления 2, с процессором Intel Core2 Quad с тактовой частотой 2,40 ГГц.


ОТКАЗ

Я знаю, что микробенчмарки бесполезны в производстве. Я также знаю, что System.currentTimeMillis() не так точно, как предполагает его название. Это то, что я заметил, когда дурачился, и мне было просто любопытно, почему это происходит; больше ничего.

Ответы [ 4 ]

5 голосов
/ 09 апреля 2010

Это интересный вопрос, но, честно говоря, я не уверен, что рассмотрение поведения Hotspot здесь даст полезную информацию. Любые ответы, которые вы получите, не будут передаваться в общем случае (потому что мы смотрим на оптимизацию, которую Hotspot выполняет в одной конкретной ситуации), поэтому они помогут вам понять, почему один неактивен быстрее другого, но они не помогут вам писать быстрее "настоящие" программы .

Также невероятно легко написать очень вводящие в заблуждение микро-тесты для такого рода вещей - посмотрите эту статью IBM DW , чтобы узнать о некоторых распространенных подводных камнях, как их избежать и некоторые общие комментарии о том, что вы делает.

Так что на самом деле это ответ без комментариев, но я думаю, что это единственный действительный ответ. Тривиальный цикл no-op во время компиляции не требует необходимости , чтобы быть быстрым, поэтому компилятор не оптимизирован для быстрой работы в некоторых из этих условий.

4 голосов
/ 09 апреля 2010

Вы, вероятно, используете 32-битную JVM. Результаты, вероятно, будут другими с 64-битной JVM. В 32-разрядной JVM int может быть отображен на собственное 32-разрядное целое число и увеличен с помощью одной операции. То же самое не держится долго, что потребует больше операций для увеличения.

См. Этот вопрос для обсуждения int и long size.

3 голосов
/ 09 апреля 2010

Мое предположение - и это только предположение - это:

JVM заключает, что первый цикл фактически ничего не делает, поэтому полностью удаляет его. Никакая переменная не «выходит» из цикла for.

Во втором случае цикл также ничего не делает. Но может случиться так, что код JVM, который определяет, что цикл ничего не делает, имеет предложение «if (type of i) == int». В этом случае оптимизация для удаления цикла бездействия работает только с int.

Оптимизация, которая удаляет код, должна гарантировать отсутствие побочных эффектов. Кодеры JVM, похоже, допустили ошибку из-за осторожности.

1 голос
/ 09 апреля 2010

Подобный микро-бенчмаркинг не имеет большого смысла, потому что результаты во многом зависят от внутренней работы Jots Hotspot.

Также обратите внимание, что значения системных часов, которые вы получаете с System.currentTimeMillis(), не имеют разрешения 1 мс во всех операционных системах. Вы не можете использовать это для очень точного определения времени очень коротких событий.

Взгляните на эту статью, в которой объясняется, почему выполнение микро-тестов в Java не так просто, как думает большинство людей: Анатомия дефектного микробенчмарка

...