2008-11-05 3 views
10

Есть ли разница в производительности между циклами for для примитивного массива?Современный цикл для примитивного массива

Предположим:

double[] doubleArray = new double[300000]; 


for (double var: doubleArray) 
    someComplexCalculation(var); 

или:

for (int i = 0, y = doubleArray.length; i < y; i++) 
    someComplexCalculation(doubleArray[i]); 

Результат теста

Я на самом деле профилированного его:

Total timeused for modern loop= 13269ms 
Total timeused for old loop = 15370ms 

Так современный цикл работает быстрее, по крайней мере, на моем Mac OSX JVM 1.5.

+0

Сколько памяти это займет. 80GB? – JesperE 2008-11-05 20:52:03

+0

Я на самом деле не думал, когда писал это ... но да. 80Gb – Dan 2008-11-05 21:06:48

+0

Собственно, он не будет компилироваться, потому что 10000000000 не является int. – 2008-11-06 00:28:22

ответ

4

Your рукописные, «старая» форма выполняет меньше инструкций и может быть. быстрее, хотя вам нужно будет профилировать его под данным компилятором JIT, чтобы точно знать. «Новая» форма, безусловно, не.

Если вы посмотрите на разобранном коде (составитель JDK Солнца 1.5), вы увидите, что «новая» форма эквивалентна следующий код:

1: double[] tmp = doubleArray; 
2: for (int i = 0, y = tmp.length; i < y; i++) { 
3: double var = tmp[i]; 
4: someComplexCalculation(var); 
5: } 

Таким образом, вы можете видеть, что больше местных переменные.Назначение doubleArray в tmp в строке 1 является «лишним», но оно не встречается в цикле и, вероятно, не может быть измерено. Назначение var по строке 3 также дополнительно. Если есть разница в производительности, это будет отвечать.

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

Это, я бы использовал новую форму, если вам не нужно что-то делать с переменной индекса. Любая разность производительности, скорее всего, будет оптимизирована компилятором JIT во время выполнения, и новая форма станет более понятной. Если вы продолжаете делать это «вручную», вы можете упустить будущие оптимизации. Как правило, хороший компилятор может хорошо оптимизировать «глупый» код, но натыкается на «умный» код.

2

Почему бы не измерить его самостоятельно?

Это звучит немного грубо, но такие вопросы очень легко проверить.

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

1

Нет никакой разницы. Java преобразует расширенное значение в обычный цикл. Улучшенный для всего лишь «синтаксический сахар». Генерируемый байт-код одинаковый для обеих петель.

5

Мое мнение таково, что вы не знаете и не должны догадываться. Попытка перехитрить компиляторов в наши дни бесплодна.

Было время, когда люди узнавали «Шаблоны», которые, казалось, оптимизировали некоторую операцию, но в следующей версии Java эти шаблоны были на самом деле медленнее.

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

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

Как раз вовремя компиляция означает, что он может иногда превосходить C, и в некоторых случаях он не может опередить статический язык ассемблера (сборка не может заранее определить, что вызов не требуется, Java может время от времени . делать только что

Подводя итог: самое значение, которое вы можете поместить в код, чтобы написать его, чтобы быть читаемыми

1

Мне очень понравился ваш вопрос, даже после моего предыдущего ответа. Поэтому я тоже решил проверить это. Я написал этот небольшой фрагмент кода (не обращайте внимания на математическую корректность относительно проверки, является ли число премьер ;-)):

public class TestEnhancedFor { 

    public static void main(String args[]){ 
     new TestEnhancedFor(); 
    } 

    public TestEnhancedFor(){ 
     int numberOfItems = 100000; 
     double[] items = getArrayOfItems(numberOfItems); 
     int repetitions = 0; 
     long start, end; 

     do { 
      start = System.currentTimeMillis(); 
      doNormalFor(items); 
      end = System.currentTimeMillis(); 
      System.out.printf("Normal For. Repetition %d: %d\n", 
        repetitions, end-start); 

      start = System.currentTimeMillis(); 
      doEnhancedFor(items); 
      end = System.currentTimeMillis(); 
      System.out.printf("Enhanced For. Repetition %d: %d\n\n", 
        repetitions, end-start); 

     } while (++repetitions < 5); 
    } 

    private double[] getArrayOfItems(int numberOfItems){ 
     double[] items = new double[numberOfItems]; 
     for (int i=0; i < numberOfItems; i++) 
      items[i] = i; 
     return items; 
    } 

    private void doSomeComplexCalculation(double item){ 
     // check if item is prime number 
     for (int i = 3; i < item/2; i+=2){ 
      if ((item/i) == (int) (item/i)) break; 
     } 
    } 

    private void doNormalFor(double[] items){ 
     for (int i = 0; i < items.length; i++) 
      doSomeComplexCalculation(items[i]); 
    } 

    private void doEnhancedFor(double[] items){ 
     for (double item : items) 
      doSomeComplexCalculation(item); 
    } 

} 

Запуск приложения дал следующие результаты для меня:

нормально. Повторение 0: 5594 Enhanced For. Повторение 0: 5594

Нормальный для. Повторение 1: 5531 Enhanced For. Повторение 1: 5547

Normal For. Повторение 2: 5532 Enhanced For. Повторение 2: 5578

Нормальный для. Повторение 3: 5531 Enhanced For. Повторение 3: 5531

Нормальный для. Повторение 4: 5547 Улучшенное для. Повторение 4: 5532

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

Среднее время (исключая первое повторение) составляет 5535,25мс для нормальной петли и 5547 мс для расширенного контура. Но мы можем видеть, что наилучшее время работы для обеих петель одинаково (5531 мс), поэтому я думаю, что мы можем прийти к выводу, что обе петли имеют одинаковую производительность - и изменения пройденного времени обусловлены другими приложениями (даже ОС) машины.

Смежные вопросы