[モダンジャワ動作]chpt7並列データ処理とパフォーマンス


データセットに関連する操作を簡単に並列に実行する方法を説明します.今回のリリースでは、パラレル・ストリームを使用してデータを並列に処理し、パラレル・ストリームのパフォーマンスを分析します.
これまで,新しいストリームインタフェースを用いてデータセットを宣言的に制御する方法について理解してきた.また、外部繰返しを内部繰返しに変更することで、ネイティブjavaライブラリはストリーム要素の処理を制御できます.
したがって,Java開発者は集合データの処理速度を速めることに悩む必要はない.最も重要な特徴は,コンピュータのマルチコアを用いてパイプ計算を実行できることである.
Java 7が現れるまで、データセットを並列に処理するのは難しい.たとえば、まずデータをサブセクションに分割し、各スレッドに割り当てます.スレッドに割り当てると、予期せぬ試合状態を避けるために適切な同期が必要になり、最終的に結果の一部をマージします.JAva 7はフォークリフト/連結フレーム機能を提供し、より簡単に並列化を実現し、エラーを最小限に抑えることができます.フォークリフト/連結フレームは7.2節で紹介されます.

へいれつりゅう


第4章では,ストリームインタフェースを用いて要素を非常に簡単に並列処理することができる.コレクションでParallelStreamを呼び出すと、パラレルストリームが生成されます.
パラレルストリームは、ストリーム要素を複数のブロックに分割して、各スレッドで処理するストリームです.したがって、パラレルストリームは、すべてのマルチコアプロセッサが各ブロックを処理するように割り当てられる.
1からnまでの加算演算の例を見てみましょう
public long iterativeSum(long n){
	long result = 0;
    for (long i = 1L; i <= n; i++){
    	result += i;
    }
    return result;
}
ただし、ストリームを使用すると、タスクをスレッド別に分割して並列処理することができます.そしてこの方法はもっと有効です.
Stream.itreate(1L, i -> i + 1)
	  .limit(n)
      .parallel()
      .reduce(0L, Long::sum);
どのスレッドを使用するか、結果変数を同期する方法、どのスレッドを使用しますか?数字はどのように生成されますか?生成された数字は誰がしますか?
パラレルストリームは、心配や心配を必要とせずにすべての問題を簡単に解決します.

00連続ストリームをパラレルストリームに変換


パラレルメソッドがシーケンスストリームで呼び出されると、既存の関数型再生演算(数値と計算)が並列に処理されます.
Stream.itreate(1L, i -> i + 1)
	  .limit(n)
      .parallel()
      .reduce(0L, Long::sum);
上記のコードは、再生操作を使用してストリーム内のすべての数値を追加します.従来のコードとは異なり,ストリームは複数のブロックに分割される.したがって、複数のブロックで並列に再生演算を行うことができる.最後に、再生演算により生成された部分結果を再生演算に統合し、ストリーム全体の再生結果を得る.
実際には、シーケンスストリームでパラレルが呼び出されても、ストリーム自体は変化しません.内部でparallelを呼び出すと、演算が並列に実行される必要があることを示すブールタグが設定されます.逆に、パラレルストリームをシーケンスストリームに変換できます.この2つの方法では、どの演算が並列に実行され、どの演算順序が実行されるかを制御できます.
stream.parallel()
	  .filter(...)
      .sequential()
      .map(...)
      .parallel()
      .reduce();
最終的に呼び出されるメソッドは、パイプライン全体に影響します.数値合計の例では、マルチコアプロセッサの並列実行を使用するとパフォーマンスが向上します.これまで,1つの演算を実行する3つの方法(繰返し式,順序式,並列式)について議論した.これらの中でどれが一番速いですか.

01フロー性能測定


パラレル化を利用すると、順序や繰返し形式よりもパフォーマンスが向上します.しかし推測と予想は危険だ.特に性能を最適化するには測定が必要である.
そこで、Java MicroBenchmark Hanessというライブラリを使用して、小さな基準を実現します.
テスト結果はfor loop、シーケンスフロー、並列フローの順であった.どうしてこんな結果になったの?

  • 重複する結果に基づいて埋め込まれたオブジェクトが作成されるため、数値を追加するには解凍する必要があります.

  • 重複作業は並列に実行可能な独立したユニットに分けにくい.

  • リプレイは実行されません.再生プロセスの開始時に完全な数値リストが用意されていないため、ストリームをブロックに分割して並列処理することはできません.

  • したがって,割り当てスレッドのオーバーヘッドのみが増加する.
  • このように手を焼くと、予想とは異なる結果を得ることがある.並列処理を誤用すると、プログラム全体のパフォーマンスが逆に悪くなります.したがって,パラレルメソッドを呼び出すと内部で何が起こるかを理解しなければならない.

    より専門的な方法を使う


    LongStream.rangeClosed()を使用して要素を作成する場合は、基本longが直接使用されるため、モザイクと取り外しのオーバーヘッドがなくなり、生成された要素をブロックに分割できます.従って、性能測定結果は、シーケンスストリームよりも速い性能を有する.
    適切なデータ構造を選択してこそ、並列実行が最適な性能を発揮することができ、関数プログラミングに比べて、関数プログラミングを使用すると、最新のマルチコアCPUが提供する並列実行能力をより簡単に直接得ることができる.
    しかし、並列化は無料ではありません.その結果、並列化によってストリーム分割、異なるスレッドでの再計算、結果値のマージなどのオーバーヘッドが発生するため、マルチコア間のデータ移動オーバーヘッドを処理する場合、マルチコア間のデータ移動オーバーヘッドを処理するよりも長い時間がかかる可能性がある.

    02パラレルストリームを正しく使用する


    パラレルストリームは、共有状態を変更するアルゴリズムを使用する場合に問題を引き起こします.リスト内の数値を繰り返すと、アキュムレータが初期化され、リスト内の各要素でナビゲートされ、アキュムレータに数値が追加されます.この場合、順次実施されるため、災害が発生します.
    複数のスレッドから同時にデータにアクセスするとrace条件の問題が発生します.最終的には並列化の特性はありません.
    共有データの状態変化を回避する方法の詳細については、18章と19章の関数プログラミングを参照してください.まず、パラレルストリームが正常に動作するには可変状態を回避しなければならないことを覚えてから、パラレルストリームを使用して適切なパフォーマンスを向上させる方法を見てください.

    03パラレルストリームを効率的に使用


    1000個以上の場合、パラレルストリームライタのように量を基準にすることはできません.でもヒントはいいです
    パラレルストリーム書き込み時のチェックリスト

  • 不確実であれば、直接測定します.順番を並べ替えるのは簡単です.しかし,無条件に変更することは万能ではなく,適切な基準で性能を直接テストすることが望ましい.

  • 朴興主義自動方式と取り外しは、パフォーマンスを大幅に低下させる可能性がある要因です.したがって,できるだけ基本型特化流を用いる.

  • limit、findFirstのような要素の順序に依存する演算は、パラレルストリームを遅くします.

  • フローで実行される総パイプラインの計算コストを考慮します.1つの要素を処理する数がQであり,実行回数がNの場合,Qが高いほど性能が改善される可能性が高い.

  • 少量のデータで使用しないでください.

  • 資料の構造が適切かどうかを確認する.LinkedListは効率的ではありません.分割するには、すべての要素を参照する必要があります.

  • 最も精密な演算のマージプロセスのオーバーヘッドが大きい場合、並列処理のメリットは減少します.パラレルストリームで得られたパフォーマンス収益は、サブストリームの一部の結果をマージする過程で相殺される可能性があるためです.