2012-01-31 2 views
2

Я тестирую производительность при добавлении целого числа в Java. То, как я это сделал, - суммирование миллиардов целых чисел. Образец файла, который я использую для тестирования, представляет собой двоичный файл 1G. Моя программа так же проста, как показано в нижеприведенном фрагменте.Целое сложение производительности в Java

int result = 0; 
FileChannel fileChannel = new FileInputStream(filename).getChannel(); 
long fileSize = fileChannel.size(); 
intBuffer = fileChannel.map(MapMode.READ_ONLY, startPosition, fileSize).asIntBuffer(); 

try { 
    while (true) { 
    result += intBuffer.get(); 
    } 
} catch (BufferUnderflowException e) { 
    System.out.println("Complete reading"); 
} 

Как вы можете видеть выше, он просто выполняет две операции в каждом цикле

  • чтения целое из файла
  • целое дополнение

Эта программа проходила около 2 минут на моя машина. Я также выполнил еще один тестовый прогон без добавления, изменив result += intBuffer.get() на result = intBuffer.get() (показано в следующем фрагменте).

int result = 0; 
FileChannel fileChannel = new FileInputStream(filename).getChannel(); 
long fileSize = fileChannel.size(); 
intBuffer = fileChannel.map(MapMode.READ_ONLY, startPosition, fileSize).asIntBuffer(); 

try { 
    while (true) { 
    result = intBuffer.get(); 
    } 
} catch (BufferUnderflowException e) { 
    System.out.println("Complete reading"); 
} 

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

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

int result = random.nextInt(); 
int other = random.nextInt(); 
int num = 1073741824/4; 
while(num-- > 0) { 
    result += other; 
} 

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

Мой вопрос

  • Что вызвало большую разницу в синхронизации между этими пробегов? Компилятор Java делает что-то для оптимизации последнего?

Любые мысли приветствуются.

+0

Возможно, вы захотите уточнить, что вы подразумеваете под «вторым». Я считаю, что это означает, что вы выполнили 'result = intBuffer.get()', но 2 ответа (пока), кажется, предполагают, что вы имеете в виду тот, где вы используете 'random.nextInt()'. – vaughandroid

+1

Это происходит потому, что ОС хранит недавно использованные файлы в памяти. Попробуйте запустить тест еще раз в обратном порядке. –

+0

@Baqueta, я скорректировал свою формулировку, чтобы сделать вопрос более ясным. – Chen

ответ

3

Это потому, что дисковый ввод-вывод очень медленный по сравнению с процессором.

В первом случае вы читаете из файла. Таким образом, вы связаны дисковым доступом.

Во втором случае это все в CPU.


Так что это не имеет никакого отношения к скорости добавления.

  • Первый случай ограничен скоростью вашего диска.
  • Второй случай (возможно) ограничен скоростью генератора случайных чисел.

А почему result = intBuffer.get(), кажется, очень быстро: (вытащил из комментариев)

Два возможных причин я могу думать:

  • Dead Code Elimination от JIT является оптимизация вне всякой последней итерации.
  • буферизацию I/O:. ОС буферизация весь файл в память после первого чтения *

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

+0

Он сказал, что его 2-й тестовый прогон не имеет никакого дополнения и просто читал из того же файла и закончил за 1 секунду. –

+0

В первом случае я также тестировал без какого-либо целочисленного добавления, заменив оператор в цикле с помощью результата 'result + = intBuffer.get()' с 'result = intBuffer.get()' и он завершается в течение 1 секунды. – Chen

+1

Это может быть связано с [Dead Code Elimination] (http://en.wikipedia.org/wiki/Dead_code_elimination). Я не уверен, хотя ... Возможно, JIT достаточно умен, чтобы понять, что имеет значение только последняя итерация ... – Mysticial

1

Большая разница в том, что вы делаете файл IO. Суммирование целых чисел не является проблемой. Но он их читает. Я не очень уверен, но я думаю, что чтение одного ГБ данных за две минуты приемлемо.

0

Это потому, что доступ к I/O - это ваша шея бутылки. Рассчитывайте время только на фазе добавления. Вы всегда можете загрузить все данные в ОЗУ (например, массив int) и начать отсчет времени с этой точки.

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

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