Потоки Java 8 медленнее, чем циклы, написанные вручную?

Я пытаюсь протестировать две разные реализации функции Java, которая проверяет, содержит ли число хотя бы одну четную цифру. В первой реализации используется рукописный цикл, а во второй - stream.

public class StreamTest {

public boolean containsEvenDigit(int n) {
    char [] digits = String.valueOf(n).toCharArray();
    for(char d : digits) {
        if (d % 2 == 0) {
            return true;
        }
    }
    return false;
}

public boolean containsEvenDigitStreams(int n) {
    return String.valueOf(n).chars().anyMatch(i -> i % 2 == 0);
}

public static void main(String[] args) {
    System.out.println("============WITHOUT STREAM=========== = ");
    long start1 = System.nanoTime();
    for(int i = 0 ; i < 1_000_000; i++) {
        (new StreamTest()).containsEvenDigit(11215 + i);
    }
    long duration1 = (long)(System.nanoTime() - start1)/1_000_000;
    System.out.println("Duration : " + duration1 + " milliseconds.");
    System.out.println();

    System.out.println("============USING STREAM=========== = ");
    long start2 = System.nanoTime();
    for(int i = 0 ; i < 1_000_000; i++) {
        (new StreamTest()).containsEvenDigitStreams(11215 + i);
    }
    long duration2 = (long)(System.nanoTime() - start2)/1_000_000;
    System.out.println("Duration : " + duration2 + " milliseconds.");
    System.out.println();

}

}

В функции main я не выводю возвращаемые значения тестируемых функций, чтобы исключить накладные расходы ввода-вывода. Результат показывает, что реализация с использованием потоков выполняется намного медленнее, чем реализация с использованием цикла.

============WITHOUT STREAM============
Duration : 119 milliseconds.

============USING STREAM============
Duration : 771 milliseconds.

Означает ли это, что потоки Java 8 медленнее, чем циклы, написанные вручную?

Обновлять: Сейчас я использую JMH для тестирования двух функций.

public class MyBenchmark {

private boolean containsEvenDigit(int n) {
    char [] digits = String.valueOf(n).toCharArray();
    for(char d : digits) {
        if (d % 2 == 0) {
            return true;
        }
    }
    return false;
}

private boolean containsEvenDigitStream(int n) {
    return String.valueOf(n).chars().anyMatch(i -> i % 2 == 0);
}

@State(Scope.Thread)
public static class MyState{
    public int x = 1_357_997_531;
}

@Benchmark
public void testLoop(MyState state, Blackhole blackhole) {
    boolean retVal = containsEvenDigit(state.x);
    blackhole.consume(retVal);
}

@Benchmark
public void testStream(MyState state, Blackhole blackhole) {
    boolean retVal = containsEvenDigitStream(state.x);
    blackhole.consume(retVal);
}

public static void main(String[] args) throws RunnerException {
    Options opt = new OptionsBuilder()
            .include(MyBenchmark.class.getSimpleName())
            .forks(1)
            .build();

    new Runner(opt).run();
}

}

На этот раз рукописный цикл превосходит поток примерно на 8. Вот сводка результатов.

Benchmark                Mode  Cnt        Score        Error  Units
MyBenchmark.testLoop    thrpt  200  3578620.170 ± 207106.919  ops/s
MyBenchmark.testStream  thrpt  200   433884.589 ±  23993.270  ops/s

См .: stackoverflow.com/questions/504103

Jorn Vernee 21.04.2018 12:18

в одном методе вы используете toCharArray(), а в другом - chars(), как узнать, нет ли разницы? вам нужно предоставить один и тот же аргумент для двух методов для тестирования

Sharon Ben Asher 21.04.2018 12:19

Это не то же самое, что stackoverflow.com/q/504103/802339. Я спросил, медленнее ли потоки Java 8, а не о написании безупречного теста.

sank 21.04.2018 12:30

См .: jaxenter.com/…

lexicore 21.04.2018 12:42

@sank Если вы напишете «Я пытаюсь сравнить две разные реализации», вполне ожидаемо, что кто-то укажет вам, как правильно написать этот тест. Если вы напишете правильно, у вас есть ответ.

lexicore 21.04.2018 12:44
«Я спросил, медленнее ли потоки Java 8» - Нет. Вы фактически спросили «Означает ли это [другими словами, ваш тест], что потоки Java 8 медленнее, чем циклы, написанные вручную?». И ответ на этот вопрос заключается в том, что ваш тест ничего не значит ... потому что он ошибочен.
Stephen C 21.04.2018 13:47

У меня есть еще один дубликат, который спрашивает когда, поток будет медленнее, чем цикл. И краткий ответ ... это сложно и зависит от версии Java.

Stephen C 21.04.2018 13:58

@StephenC Сейчас я тестирую тесты с помощью JMH. Результаты такие же.

sank 23.04.2018 17:00

ОК. Теперь как иметь единую «точку данных». Это говорит о том, что для этого конкретного примера (закодированного так, как вы это сделали) реализация цикла выполняется быстрее, чем реализация потока. Но вы не можете сделать обобщение на основе одной точки данных / одного примера до вывода, который пытаетесь сделать. Итак, еще раз, нет, это не значит.

Stephen C 24.04.2018 01:21
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
9
183
0

Другие вопросы по теме