Хобрук: Ваш путь к мастерству в программировании

Производительность Math.pow в Java 8 и Java 7

Я запустил следующую программу в другой версии Java.

final double[] values = new double[10000];
final long start = System.currentTimeMillis();
double sum = 0;

for (int i = 0; i < values.length; i++)
    sum += Math.pow(values[i], 2);

final long elapsed = System.currentTimeMillis() - start;
System.out.println("Time elapse :: " + elapsed);

Ява 7: вывод

Прошедшее время :: 1

Java 8: вывод

Прошло время :: 7

Почему в Java 8 есть проблема с производительностью по сравнению с 7?


  • Возможно, ваш набор данных слишком мал для получения надежных результатов. Можете ли вы примерить большие наборы? 04.08.2015
  • В настоящее время я пытаюсь с 10000 удвоить, я пробовал и с 1000000 удвоить, но получаю тот же результат. 04.08.2015
  • Избегайте ошибок при сравнительном анализе JVM oracle .com/technetwork/articles/java/ 04.08.2015
  • Почему вас беспокоит, что один вызов pow займет 0,0000007 с вместо 0,0000001 с? Будете ли вы делать это так много раз, что это имеет значение? :-) 04.08.2015
  • лучше использовать values[i] * values[i], так как это быстрее, чем math.pow 04.08.2015
  • Вы всегда вычисляете значение Math.pow(0, 2) или инициализируете свой массив случайными значениями? 04.08.2015
  • Прочтите это: Как мне написать правильный микро- тест в Java? 04.08.2015
  • @dotvav: Спасибо, похоже, это известная проблема с функцией Java 8 Math.pow. 04.08.2015
  • Проблемы производительности с Math.pow объясняются здесь 04.08.2015
  • Я оспариваю дублирующийся статус этого вопроса. Код OP не доказывает, что он действительно наблюдает эту конкретную аномалию, которая присутствует только в некоторых очень специфических (и устаревших) версиях JDK. 04.08.2015
  • @MarkoTopolnik Может быть, это не совсем та же проблема, но причина определенно та же. Описанное поведение можно легко воспроизвести с помощью JDK 7u25 по сравнению с JDK 8. Хотя тест OP не является правильным эталоном, он измеряет интерпретируемую производительность Math.pow, который был методом Java в JDK 7u25, но стал собственным методом в JDK 8. 04.08.2015
  • @apangin Но мои измерения воспроизводят наблюдения ОП, если я использую недостаточный прогрев. Так что никто толком сказать не может. 04.08.2015
  • @MarkoTopolnik Мое объяснение не противоречит вашим наблюдениям. Недостаточный прогрев => выполнение в интерпретируемом режиме => медленный собственный вызов в Java 8 по сравнению с быстрым случаем в Java 7. При достаточном прогреве метод компилируется JIT, а собственный вызов заменяется встроенным JVM. 04.08.2015
  • @apangin Если вы ограничиваете объяснение поведением, характерным для интерпретируемого кода, оно работает. Однако как это, так и повторяющиеся вопросы и ответы заявляют / подразумевают, что некоторые выпуски Java демонстрируют снижение производительности для возведения в квадрат с pow. Мы не можем сказать, наблюдает ли ОП эту конкретную регрессию или нет. 04.08.2015
  • @apangin Изучая ваш ответ о дубликате и связанный с ним билет JDK, выясняется, что регрессия происходит только после JIT-компиляции: это не собственный метод, вызываемый StrictMath.pow(), а скорее в другой встроенной функции, представленной в JDK 7u40, в которой не было специального случая для квадратов. Таким образом, нет прогрева —> нет наблюдения за регрессом производительности, описанным в дубликате. 04.08.2015

Ответы:


1

Прежде всего, в вашем тесте отсутствует прогрев. Вот более реалистичный код теста:

public class Test
{

  public static void main(String[] args) {
    final Random rnd = new Random();
    for (int i = 0; i < 20; i++) {
      final double[] values = new double[10000];
      for (int j = 0; j < values.length; j++)
        values[j] = rnd.nextDouble();
      testPow(values);
    }
  }

  private static void testPow(double[] values) {
    final long start = System.nanoTime();
    double sum = 0;
    for (int i = 0; i < values.length; i++)
      sum += Math.pow(values[i], 2);
    final long elapsed = System.nanoTime() - start;
    System.out.println("Sum: " + sum + "; Time elapse :: " + TimeUnit.NANOSECONDS.toMillis(elapsed));
  }
}

Я запустил его на Java 8, и он дал 9 мс для миллиона элементов. На Java 6 это дало 62 миллисекунды. (извините, у меня не установлен JDK 7.)

С другой стороны, если я не инициализирую массив (как вы), то я получаю 0,9 мс для миллиона элементов, тогда как Java 6 остается прежним.

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

04.08.2015
Новые материалы

Решения DBA Metrix
DBA Metrix Solutions предоставляет удаленного администратора базы данных (DBA), который несет ответственность за внедрение, обслуживание, настройку, восстановление базы данных, а также другие..

Начало работы с Блум
Обзор и Codelab для генерации текста с помощью Bloom Оглавление Что такое Блум? Некоторые предостережения Настройка среды Скачивание предварительно обученного токенизатора и модели..

Создание кнопочного меню с использованием HTML, CSS и JavaScript
Вы будете создавать кнопочное меню, которое имеет состояние наведения, а также позволяет вам выбирать кнопку при нажатии на нее. Финальный проект можно увидеть в этом Codepen . Шаг 1..

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

Классы в JavaScript
class является образцом java Script Object. Конструкция «class» позволяет определять классы на основе прототипов с чистым, красивым синтаксисом. // define class Human class Human {..

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

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