PR

ストリームの生成

 ここでクイズをやってみましょう。リスト8のsumIterateメソッドとsumRangeメソッドはどちらがパフォーマンスがよいでしょうか。

リスト8 平均の算出

    private OptionalDouble sumIterate() {
        return IntStream.iterate(0, i -> i++)
                        .limit(1_000_000)
                        .parallel()
                        .average();
    }
     
    private OptionalDouble sumRange() {
        return IntStream.range(0, 1_000_000)
                        .parallel()
                        .average();
    }

 sumIterateメソッドとsumRangeメソッドの違いは、IntSreamオブジェクトの生成にあります。sumIterateメソッドがiterateメソッドを使用してIntStreamオブジェクトを生成ししているのに対し、sumRangeメソッドはとrangeメソッドを使用しています。

 これだけの違いなのですが、パフォーマンスは大きく違います。悪いことに、どちらか一方はシーケンシャルなストリームよりパフォーマンスが落ちてしまいます。

 では、iterateメソッドとrangeメソッドの違いはどこにあるでしょうか。iterateメソッドはlimitメソッドと合わせて使っていることから分かるように、生成したストリームが無限ストリームになります。

 今後パラレルストリームの内部構造を解説する予定ですが、パラレルストリームのパラレル処理は分割統治法を使用しています。分割統治法はFork/Join Frameworkの解説で紹介したように、再帰的にタスクのサイズを半分にしていき、タスクの粒度を細かくする手法です。

 パラレルストリームでも要素を半分にしていくことで、処理単位を小さくしていきます。ここで重要なのが半分にするためには、要素数が分からないといけないということです。