Почему функциональный стиль поиска работает быстрее, чем императив в Java - PullRequest
0 голосов
/ 08 февраля 2019

Я пытаюсь выяснить, почему компилятор просматривает коллекцию, используя функциональный стиль, а не императив.Вот простой пример, где функциональный поиск идет первым и занимает 9,5 секунды, а императив следует сразу же с 10,3.Как только я переставляю их и ставлю императив перед функционалом, результаты становятся похожими: 10.1 и 10.29


Я добавил некоторые изменения, основанные на ответах пользователей, которые делают мой код более корректным.Теперь бенчмарк запускается в нужный момент времени и отсчитывает время того, что мне точно нужно.Но вопрос остается без ответа.Несмотря на то, что я запускаю два независимых таймера, для каждого цикла функциональный цикл завершается, но поиск выполняется намного быстрее, чем Imperative.1,03 против 0,3.

import java.util.*;
public class Main
{
    public static void main(String[] args)
    {
    List<Integer> numbers = new ArrayList();
    int size = 200000000;
    //add objects to collection
       for(int i = 0; i <= size; i++)
       {
       numbers.add(i);
       }
    //functional
    long timer = System.nanoTime();
       if(numbers.contains(size))
       {
       System.out.println(System.nanoTime() - timer) / 1000000000.0);
       }
    //imperative
    timer = System.nanoTime();
       for(Integer num : numbers)
       {
          if(num.equals(size))
          {
        System.out.println(System.nanoTime() - timer) / 1000000000.0);
          break;
          }
       }
    }
}

Итак, вопрос такой:

  • Почему функциональный поиск завершается быстрее?

Ценю ваш ответ

Ответы [ 3 ]

0 голосов
/ 08 февраля 2019

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

Попробуйте еще раз, как это:

import java.util.*;
public class Main
{
    public static void main(String[] args)
    {
    List<Integer> numbers = new ArrayList<>();

    int size = 200000000;
    //add objects to collection
       for(int i = 0; i <= size; i++)
       {
       numbers.add(i);
       }
    //functional
       long timer = System.nanoTime(); //take start time here
       if(numbers.contains(size))
       {
       System.out.println(System.nanoTime() - timer) / 1000000000.0);
       }
    //imperative
       long timer = System.nanoTime(); //take a new start time for the second test
       for(Integer num : numbers)
       {
          if(num.equals(size))
          {
        System.out.println(System.nanoTime() - timer) / 1000000000.0);
          break;
          }
       }
    }
}
0 голосов
/ 08 февраля 2019

То, как вы вычислили длительность для каждой операции, отключено.

  • Первая напечатанная длительность на самом деле показывает, сколько времени требуется для добавления всех элементов всписок И найти элемент с помощью contains
  • Второй занимает первая продолжительность И продолжительность последнего цикла

Вот как это исправить

List<Integer> numbers = new ArrayList<>();
int size = 100000;

for (int i = 0; i <= size; i++)
    numbers.add(i);

long timer = System.nanoTime();
if (numbers.contains(size))
    System.out.println((System.nanoTime() - timer) / 1000000000.0);

timer = System.nanoTime();

for (Integer num : numbers) {
    if (num.equals(size)) {
        System.out.println((System.nanoTime() - timer) / 1000000000.0);
        break;
    }
}
0 голосов
/ 08 февраля 2019

ArrayList использует такой же цикл, как и у вас: -

for (int i = start; i < end; i++) {
    if (o.equals(es[i])) {
        return i;
    }
}

Так что не будет практической разницы в производительности.

Небольшая разница в производительности вывидеть можно, даже если вы запускаете один и тот же код несколько раз.Это может произойти из-за множества факторов, включая планирование ЦП и т. Д.

...