Java Поток работает медленнее, чем для цикла - PullRequest
0 голосов
/ 19 апреля 2020

Мне сказали, что Java Stream - хороший выбор для обработки большого количества данных, и недавно я провел сравнительный тест. Однако результат теста неожиданный:

Вопрос от CodeWar:

Предположим, что изначально есть метро с 100 людьми, на каждой остановке в метро находятся несколько человек и несколько человек. вне. Цель состоит в том, чтобы подсчитать количество людей, оставшихся в метро после большого количества остановок (100000).

Вот мой код:

import java.util.ArrayList;

public class Metro1 {
    private final static int STOPS = 100000;
    private static ArrayList<int[]> metro = new ArrayList<int[]>();

    public static int sum1() {
        int sum = 0;
        for(int[] x: metro) {
            sum +=x[0] - x[1];
        }
        return sum;
    }

    public static int sum2() {
        return metro.stream()
                .mapToInt(x -> x[0]-x[1])
                .sum();
    }
    public static void main(String[] args) {
        long start=0;
        long end = 0;
        metro.add(new int[] {100,0});
        for(int i=1;i<STOPS;i++) {
            int in = (int) Math.round(Math.random() * 10);
            int out = (int) Math.round(Math.random() * 10);
            metro.add(new int[] {in,out});
        }
        System.out.println("Stops: " + metro.size());

        start = System.currentTimeMillis();
        System.out.println("sum1: " + sum1());
        end = System.currentTimeMillis();
        System.out.println("sum1 (for loop): " + String.valueOf(end-start) + " milliseconds.");


        start = System.currentTimeMillis();
        System.out.println("sum2: " + sum2());
        end = System.currentTimeMillis();
        System.out.println("sum1 (stream): " + String.valueOf(end-start) + " milliseconds.");

    }

}

Я запустил код в Eclipse и я обнаружил, что sum1 намного быстрее, чем sum2:

Stops: 100000
sum1: 79
sum1 (for loop): 6 milliseconds.
sum2: 79
sum1 (stream): 68 milliseconds.

Я думал, что код достаточно прост, но почему поток медленнее, чем для l oop?

Спасибо,

Алекс

Ответы [ 2 ]

1 голос
/ 19 апреля 2020

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

Но что касается вашего примера.

  • Опираясь на простые тесты производительности с использованием внутренних часов (хотя я сделать это тоже) не самый лучший способ точно оценить производительность. Для тестирования используйте что-то вроде Java Microbench Harness .
  • Что касается вашего результата, попробуйте выполнить следующее:

    • Изменить STOPS to 100_000_000
    • Измените ваш поток на
      return metro.stream().parallel() .mapToInt(x -> x[0]-x[1]) .sum();

Вот результаты на моем Windows, quad core i7 laptop

Stops: 100000000
sum1: -7073
sum1 (for loop): 908 milliseconds.
sum2: -7073
sum1 (stream): 518 milliseconds.

0 голосов
/ 19 апреля 2020

Потоковый API больше предназначен для удобства чтения и поддержки кода. Циклы for могут обеспечить лучшую производительность, но иногда производительность не может быть важной метрикой c для измерения. В равной степени важно иметь поддерживаемый код.

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

...