This code is benchmarking 3 different ways to compute the sum of the reciprocals of the elements of a double[].
- a
for-loop - Java 8 streams
- the
coltmath library
What is the reason that the computation using a simple for-loop is ~400 times faster than the one using streams? (Or is there anything needs to be improved in the benchmarking code? Or a faster way of computing this using streams?)
Code :
import java.util.Arrays; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.IntStream; import cern.colt.list.DoubleArrayList; import cern.jet.stat.Descriptive; import org.openjdk.jmh.annotations.*; @State(Scope.Thread) public class MyBenchmark { public static double[] array; static { int num_of_elements = 100; array = new double[num_of_elements]; for (int i = 0; i < num_of_elements; i++) { array[i] = i+1; } } @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void testInversionSumForLoop(){ double result = 0; for (int i = 0; i < array.length; i++) { result += 1.0/array[i]; } } @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void testInversionSumUsingStreams(){ double result = 0; result = Arrays.stream(array).map(d -> 1/d).sum(); } @Benchmark @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) public void testInversionSumUsingCernColt(){ double result = Descriptive.sumOfInversions(new DoubleArrayList(array), 0, array.length-1); } } Results:
/** * Results * Benchmark Mode Cnt Score Error Units * MyBenchmark.testInversionSumForLoop avgt 200 1.647 ± 0.155 ns/op * MyBenchmark.testInversionSumUsingCernColt avgt 200 603.254 ± 22.199 ns/op * MyBenchmark.testInversionSumUsingStreams avgt 200 645.895 ± 20.833 ns/o */ Update: these results show Blackhome.consume or return is necessary to avoid jvm optimization.
/** * Updated results after adding Blackhole.consume * Benchmark Mode Cnt Score Error Units * MyBenchmark.testInversionSumForLoop avgt 200 525.498 ± 10.458 ns/op * MyBenchmark.testInversionSumUsingCernColt avgt 200 517.930 ± 2.080 ns/op * MyBenchmark.testInversionSumUsingStreams avgt 200 582.103 ± 3.261 ns/op */ oracle jdk version "1.8.0_181", Darwin Kernel Version 17.7.0
loopcase. You need to "consume" result either by callingBlackhole.consumeor by simply addingreturn result;at the end of benchmark method.