LoginSignup
6
5

More than 5 years have passed since last update.

Stream/ParallelStream/Forが複数コア使ってくれるのか気になったので調べてみた

Last updated at Posted at 2017-01-20

※2017.1.23 もろもろ勘違いして記載していたので大幅書き換え

Forループって複数コア使ってくれるの? Stream/ParallelStreamは?
とか気になったの簡単に比べてみた。

StreamとParallelStreamの挙動についてはJavaOne2013のJava 8 Streams: Lambda in Top Gearのスライドを見るのが良さげ。

一応どの計測も2,3回実行した後に行っています。

Forループ

public class StreamTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        for (int i = 1; i <= 200000; i++) {
            list.add(String.valueOf(i));
        }

        long start = System.currentTimeMillis();

        String str = "";
        for (String val : list) {
            str += val;
        }
        System.out.println(str);

        long end = System.currentTimeMillis();
        System.out.println((end - start)  + "ms");
    }
}

所要時間は42801ms

for.png

一応4コアとも使っているっぽい。けどコアあたりのCPU使用率は100%にはならず。

Stream

public class StreamTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        for (int i = 1; i <= 200000; i++) {
            list.add(String.valueOf(i));
        }

        long start = System.currentTimeMillis();

        Optional<String> str = list.stream().reduce((val1, val2) -> val1 + val2);
        System.out.println(str);

        long end = System.currentTimeMillis();
        System.out.println((end - start)  + "ms");
    }
}

所要時間は41039ms

stream.png

Forループとほぼ同じ。全体に負荷が少ないかなー、という感じ。

ParallelStream

public class StreamTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

        for (int i = 1; i <= 200000; i++) {
            list.add(String.valueOf(i));
        }

        long start = System.currentTimeMillis();

        Optional<String> str = list.parallelStream().reduce((val1, val2) -> val1 + val2);
        System.out.println(str);

        long end = System.currentTimeMillis();
        System.out.println((end - start)  + "ms");
    }
}

所要時間は1937ms

parallelStream.png

一瞬全コアが100%になってすぐに終わる。20倍くらい早い。ちなみに要素数を減らすと差は小さくなっていくので、要素数が多ければ多いほど差が出ると思われる。

まとめ

使える場所では 処理する要素数が多くなる場所では)ParallelStreamを積極的に検討していくべき。

For/Streamに関しては複数コアに処理を振り分けてはいるものの、順序を保証するための同期処理でCPU待ちが発生しているように見える。なのでコアあたりの使用率が100%にならず、処理時間も長くかかる。

その分、ParallelStreamでは同期による待ちがない分、CPUが常に稼働している状態になり使用率が100%まで上がっている様子。

Forが複数コア利用しているのが予想外だったけど、それ以外は思っていた通りの挙動だったので色々納得。

ちなみに今回のテストだとParallelStreamでも処理順序が乱れていなかったんだけれど、おそらくループ内の処理時間が一定だったからたまたま順序が維持されたのだと思う。
逆にFor/Streamでも同期チェック時はほぼ必ず次の処理に行ける判定だった(待ち判定はなかった)と思うが、それでもこれだけの速度差が出ているということは、順序保証のオーバーヘッドはだいぶ大きいのかな。

処理順序というか、出力結果の順はStreamとParallelStreamの違いには直接関係なかった。で、速度差については純粋な計算量でした。
ParallelStreamについて完全に勘違いしていたよ……Java 8 Streams: Lambda in Top Gearの45:15あたりを参照。コメント指摘感謝。

6
5
3

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
6
5