LoginSignup
7
7

More than 5 years have passed since last update.

Java 8 Stream API 性能測定 - IntStream.sum()

Last updated at Posted at 2014-09-05

はじめに

Java SE 8のIntStream.sum()の性能を測定してみました。
IntStream.sum()は、並列処理のコストが低く、並列化すれば性能が向上するだろうという期待がありました。

性能測定

1~100,000の総和($\sum_{i=1}^n i$)を求めます。
次の3通りの処理方法における処理時間を出力します。

  1. 単純なfor文で総和を計算
  2. IntStream.sum()で計算
  3. IntStream.sum()を並列で計算

プログラム

Sum.java
public class Sum {
    private static final int SIZE = 100_000;

    public static void main(String[] args){
        System.out.println("os.arch="+System.getProperty("os.arch"));
        System.out.println("os.name="+System.getProperty("os.name"));
        System.out.println("os.version="+System.getProperty("os.version"));
        System.out.println("java.version="+System.getProperty("java.version"));
        System.out.println("java.vm.info="+System.getProperty("java.vm.info"));
        System.out.println("java.vm.name="+System.getProperty("java.vm.name"));
        System.out.println("sun.management.compiler="+System.getProperty("sun.management.compiler"));
        System.out.println("poolParallelism="+java.util.concurrent.ForkJoinPool.getCommonPoolParallelism());
        //warming up
        for(int i=0; i<10_000; i++){
            createIntStream().sum();
            createIntStream().parallel().sum();
        }
        //process
        System.out.println();
        sum000();
        sum001();
        sum002();
    }

    private static java.util.stream.IntStream createIntStream(){
        return java.util.stream.IntStream.rangeClosed(1, SIZE);
    }

    static void sum000(){
        final long start = System.nanoTime();
        int sum = 0;
        for(int i=0; i<=SIZE; i++){
            sum += i;
        }
        result("sum000", sum, start);
    }

    static void sum001(){
        final long start = System.nanoTime();
        result("sum001", createIntStream().sum(), start);
    }

    static void sum002(){
        final long start = System.nanoTime();
        result("sum002", createIntStream().parallel().sum(), start);
    }

    static void result(String prefix, int sum, long start){
        final long elapsed = System.nanoTime()-start;
        System.out.println(prefix+": sum="+sum+", elapsed="+elapsed);
    }
}

測定環境

Key Value
CPU Intel Core i7-2670QM CPU @ 2.20GHz コア数4 スレッド数8
RAM 8GB
OS Windows 7 Home Premium SP1 64ビット版
Java Java SE 8 Update 20

測定結果

os.arch=amd64
os.name=Windows 7
os.version=6.1
java.version=1.8.0_20
java.vm.info=mixed mode
java.vm.name=Java HotSpot(TM) 64-Bit Server VM
sun.management.compiler=HotSpot 64-Bit Tiered Compilers
poolParallelism=7


1回目
sum000: sum=705082704, elapsed=3846275
sum001: sum=705082704, elapsed=113359
sum002: sum=705082704, elapsed=429644
2回目
sum000: sum=705082704, elapsed=1785288
sum001: sum=705082704, elapsed=50848
sum002: sum=705082704, elapsed=229050
3回目
sum000: sum=705082704, elapsed=2575069
sum001: sum=705082704, elapsed=74173
sum002: sum=705082704, elapsed=332147

まとめ

  1. あらかじめウォーミングアップしておけば、単純なfor文よりもStreamを使った方が性能が良くなりました。
  2. ただし、sum()をパラレルで実行すると、シーケンスよりも性能が悪化しました。(原因はこれから検証する)
  3. 要素数を10万→1000万に増やしても(10万でも1000万でも総和がオーバーフローするが)、パラレル処理の性能が悪かったです。

お願い

別の性能測定方法(別のプログラム)や、別の環境(CPU、コア数、OS)では、性能測定の結果が違うよという事例がありましたら、コメントをいただけると嬉しいです。

7
7
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7