Forwardループと `List`の逆ループについてのhttps://openjdk.java.net/projects/code-tools/jmh/[JMHベンチマークテスト]逆ループについての神話は速いです、これは本当ですか?

テスト済み

前方ループ

    for (int i = 0; i < aList.size(); i++) {
        String s = aList.get(i);
        System.out.println(s);
    }

逆ループ

    for (int i = aList.size() - 1; i >= 0; i--) {
        String s = aList.get(i);
        System.out.println(s);
    }

1.フォワードループとリバースループ

100万と1000万のStringオブジェクトを含むリストをループする。

BenchmarkForwardReverseLoop.java

package com.mkyong.benchmark;

import org.openjdk.jmh.annotations.** ;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Fork(value = 1, jvmArgs = {"-Xms2G", "-Xmx2G"})
@Warmup(iterations = 5)
@Measurement(iterations = 10)
@State(Scope.Benchmark)
public class BenchmarkForwardReverseLoop {

    @Param({"1000000", "10000000"})
    private int N;

    private List<String> DATA__FOR__TESTING = createData();

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

        new Runner(opt).run();
    }

    @Setup
    public void setup() {
        DATA__FOR__TESTING = createData();
    }

    @Benchmark
    public void forwardLoop(Blackhole bh) {
        for (int i = 0; i < DATA__FOR__TESTING.size(); i++) {
            String s = DATA__FOR__TESTING.get(i);
            bh.consume(s);
        }
    }

    @Benchmark
    public void reverseLoop(Blackhole bh) {
        for (int i = DATA__FOR__TESTING.size() - 1; i >= 0; i--) {
            String s = DATA__FOR__TESTING.get(i);
            bh.consume(s);
        }
    }

    private List<String> createData() {
        List<String> data = new ArrayList<>();
        for (int i = 0; i < N; i++) {
            data.add("Number : " + i);
        }
        return data;
    }

}

2.結果

$ java -jar target\benchmarks.jar BenchmarkForwardReverseLoop

# JMH version: 1.21
# VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10
# VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe
# VM options: -Xms2G -Xmx2G
# Warmup: 5 iterations, 10 s each
# Measurement: 10 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop
# Parameters: (N = 1000000)

# Run progress: 0.00% complete, ETA 00:10:00
# Fork: 1 of 1
# Warmup Iteration   1: 5.333 ms/op
# Warmup Iteration   2: 5.300 ms/op
# Warmup Iteration   3: 5.210 ms/op
# Warmup Iteration   4: 5.241 ms/op
# Warmup Iteration   5: 5.236 ms/op
Iteration   1: 5.127 ms/op
Iteration   2: 5.089 ms/op
Iteration   3: 5.110 ms/op
Iteration   4: 5.148 ms/op
Iteration   5: 5.233 ms/op
Iteration   6: 5.156 ms/op
Iteration   7: 5.160 ms/op
Iteration   8: 5.605 ms/op
Iteration   9: 5.169 ms/op
Iteration  10: 5.130 ms/op


Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop":
  5.193 ±(99.9%) 0.227 ms/op[Average]  (min, avg, max) = (5.089, 5.193, 5.605), stdev = 0.150
  CI (99.9%):[4.966, 5.419](assumes normal distribution)


# JMH version: 1.21
# VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10
# VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe
# VM options: -Xms2G -Xmx2G
# Warmup: 5 iterations, 10 s each
# Measurement: 10 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop
# Parameters: (N = 10000000)

# Run progress: 25.00% complete, ETA 00:07:31
# Fork: 1 of 1
# Warmup Iteration   1: 61.361 ms/op
# Warmup Iteration   2: 61.189 ms/op
# Warmup Iteration   3: 61.570 ms/op
# Warmup Iteration   4: 61.662 ms/op
# Warmup Iteration   5: 61.604 ms/op
Iteration   1: 61.010 ms/op
Iteration   2: 61.066 ms/op
Iteration   3: 62.129 ms/op
Iteration   4: 61.854 ms/op
Iteration   5: 61.248 ms/op
Iteration   6: 61.104 ms/op
Iteration   7: 64.452 ms/op
Iteration   8: 62.398 ms/op
Iteration   9: 62.766 ms/op
Iteration  10: 66.125 ms/op


Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.forwardLoop":
  62.415 ±(99.9%) 2.535 ms/op[Average]  (min, avg, max) = (61.010, 62.415, 66.125), stdev = 1.677
  CI (99.9%):[59.880, 64.950](assumes normal distribution)


# JMH version: 1.21
# VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10
# VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe
# VM options: -Xms2G -Xmx2G
# Warmup: 5 iterations, 10 s each
# Measurement: 10 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop
# Parameters: (N = 1000000)

# Run progress: 50.00% complete, ETA 00:05:02
# Fork: 1 of 1
# Warmup Iteration   1: 6.220 ms/op
# Warmup Iteration   2: 5.861 ms/op
# Warmup Iteration   3: 5.955 ms/op
# Warmup Iteration   4: 5.919 ms/op
# Warmup Iteration   5: 6.142 ms/op
Iteration   1: 5.840 ms/op
Iteration   2: 5.864 ms/op
Iteration   3: 5.892 ms/op
Iteration   4: 6.212 ms/op
Iteration   5: 5.911 ms/op
Iteration   6: 5.906 ms/op
Iteration   7: 6.055 ms/op
Iteration   8: 6.210 ms/op
Iteration   9: 6.095 ms/op
Iteration  10: 5.821 ms/op


Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop":
  5.980 ±(99.9%) 0.227 ms/op[Average]  (min, avg, max) = (5.821, 5.980, 6.212), stdev = 0.150
  CI (99.9%):[5.754, 6.207](assumes normal distribution)


# JMH version: 1.21
# VM version: JDK 10.0.1, Java HotSpot(TM) 64-Bit Server VM, 10.0.1+10
# VM invoker: C:\Program Files\Java\jre-10.0.1\bin\java.exe
# VM options: -Xms2G -Xmx2G
# Warmup: 5 iterations, 10 s each
# Measurement: 10 iterations, 10 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Average time, time/op
# Benchmark: com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop
# Parameters: (N = 10000000)

# Run progress: 75.00% complete, ETA 00:02:30
# Fork: 1 of 1
# Warmup Iteration   1: 55.012 ms/op
# Warmup Iteration   2: 54.479 ms/op
# Warmup Iteration   3: 54.497 ms/op
# Warmup Iteration   4: 54.677 ms/op
# Warmup Iteration   5: 54.287 ms/op
Iteration   1: 54.361 ms/op
Iteration   2: 54.432 ms/op
Iteration   3: 54.367 ms/op
Iteration   4: 54.518 ms/op
Iteration   5: 54.497 ms/op
Iteration   6: 54.369 ms/op
Iteration   7: 54.698 ms/op
Iteration   8: 54.393 ms/op
Iteration   9: 54.377 ms/op
Iteration  10: 54.675 ms/op


Result "com.mkyong.benchmark.BenchmarkForwardReverseLoop.reverseLoop":
  54.469 ±(99.9%) 0.193 ms/op[Average]  (min, avg, max) = (54.361, 54.469, 54.698), stdev = 0.127
  CI (99.9%):[54.276, 54.661](assumes normal distribution)


# Run complete. Total time: 00:10:04

REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
experiments, perform baseline and negative tests that provide experimental control, make sure
the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
Do not assume the numbers tell you what you want them to tell.

Benchmark                                     (N)  Mode  Cnt   Score   Error  Units
BenchmarkForwardReverseLoop.forwardLoop   1000000  avgt   10   5.193 ± 0.227  ms/op
BenchmarkForwardReverseLoop.forwardLoop  10000000  avgt   10  62.415 ± 2.535  ms/op
BenchmarkForwardReverseLoop.reverseLoop   1000000  avgt   10   5.980 ± 0.227  ms/op
BenchmarkForwardReverseLoop.reverseLoop  10000000  avgt   10  54.469 ± 0.193  ms/op

  • 結果** :通常の順方向ループは100万ループで高速ですが、1000万ループでは逆ループが速くなります。しかし、その違いはそれほど重要ではありません。

ソースコードをダウンロードする

$ gitクローンhttps://github.com/mkyong/jmh-benchmark $ mvnパッケージ$ java -jar target \ benchmarks.jar BenchmarkForwardReverseLoop

参考文献

  1. link://java/reverse-loop-for-forward-loop-in-performance-java/[Java

    • 逆ループ対前進ループ]

  2. リンク://java/java-jmh-benchmark-tutorial/[Java JMH Benchmark Tutorial]


  3. https://arnaudroger.github.io/blog/2017/06/15/forward-vs-backward-loop.html

    [Why

逆ループは高速ではありません]