web-dev-qa-db-ja.com

Javaビデオアプリにコンシューマー/プロデューサーパターンを実装する必要があります。実装している場合、どのようにですか?

デスクトップJava 8.で小さなビデオフレーム分析アプリを作成しました。各フレームで、データを抽出します(5倍になりましたが、将来1920x1080x3 OpenCV Matに拡張される可能性があります) )このデータをデータベース(Java DBなど)に保存して、時系列分析を実行し、定期的に結果をユーザーに返します。

データベースに書き込み、シングルスレッドでアプリを実行する場合のハードドライブアクセス時間を心配しています。私に発生した最善の解決策は、マルチスレッドでプロデューサー/コンシューマーパターンを実装することです。私が見つけた例はすべて3つのスレッドを実装しています:

  1. メインスレッド
  2. プロデューサースレッド
  3. 消費者スレッド

2スレッドの実装と比較して、それを行うことには利点がありますか?

  1. メインスレッドとプロデューサースレッド
  2. 消費者スレッド

そして、それはデータベースでリアルタイムデータを処理する正しい方法ですか?

PS:上記の質問が尋ねられた here が、代わりにSE.programmersで尋ねた方がよいと言われました。

4
Raoul

これらの選択の違いは、スレッドへのタスク割り当てのアフィニティにあります。

以前の質問 で説明したように、このアフィニティを実装するかどうかは完全にあなたの選択です。スレッドに対するタスクの親和性なしにマルチスレッドを実装する方法があります。

プロデューサー-コンシューマーパターンは、次の場合に適しています。

  • データフローパイプラインは線形です-データのフローに分岐や結合はありません
    • プロデューサーには1つの出力があります
    • 消費者には1つの入力があります
    • その間のすべてのステージには、入力と出力が1つずつあります
  • データはシーケンシャルです
    • 各データに連続的に増加する番号がタグ付けされている場合、すべてのステージで、連続的に増加する同じ値でデータが到着します。
    • 中間の各ステージでは、受信したアイテムごとに1つの出力アイテムを生成する必要があります。
    • この制限を緩和することは可能です 私が他の場所でコメントで説明したように 。一般に、FIFOキューにはこの制限がありません。
  • CPU使用率を最大化することが目標ではない場合(*)。
    • 一般に、Producer-Consumerパターンは複数のコアを利用できますが、ステージ数よりも多くのコアを利用しません。
    • ボトルネックが存在する場合(つまり、他のステージと比較して処理に最も時間がかかるステージがある場合)、このステージのスループットがシステム全体のスループットを決定します。

スループット(*)を最大化するには、一般的に次のことを試みます。

  • パイプラインを細かい段階に分割します。
    • これは CPU命令パイプラインの設計 で利用されているアイデアです。
    • ステージを追加するたびにオーバーヘッドが増えるため、慎重な検討が必要です。
  • いくつかの中間ステージを並行して実行できるようにします。
    • CPUの例えは、スーパースカラーアーキテクチャでの 実行ユニット の重複です。
    • ソフトウェアでは、慎重に選択されたいくつかのステージが複数のスレッドによって実行されます。
    • これらのスレッドは、単一のFIFOキューからフィードし、各データを個別に処理してから、それらの出力を単一のスレッドセーフな並べ替えキュー(*)に送信します。
  • ボトルネック段階の最適化に焦点を当てます。例:
    • アルゴリズムの最適化。
    • SIMDプログラミングなどのマイクロ最適化。
    • GPUやFPGAなどの特殊な処理デバイスへのオフロード。

(*)スループットの最大化-1秒あたりに処理されるビデオフレームの数-が最終的な目標です。 CPU使用率を最大化しない。

アルゴリズムの改善などの一部の最適化により、そのステージのCPU使用率が低下しますが、全体的な効率が向上するため、実行されるCPU命令の総数を少なくして同じ結果を計算できます。

(*)[0][1]のタグが付いた2つのデータが処理されると、[1]の出力が事前に完了する場合があるため、並べ替えキューが必要です。パイプラインの順序付けプロパティを保持するには、[1]の出力が準備できるまで、[0]の出力を保持する必要があります。

これらの変更がスループットを望ましいレベルに最大化するのに十分でない場合、単一パイプラインのプロデューサー/コンシューマーパターンから離れて、データフローまたはデータグラフフレームワークに移動することもできます。

より一般的なデータフローまたはデータグラフフレームワークでは:

  • データフローグラフは線形である必要はありません。処理段階の有向非循環グラフ(DAG)を使用できます。
  • タスクにはスレッドとの親和性はありません。
  • データ依存性パスで明示的にモデル化されていない限り、すべてのステージはデフォルトでメモリレス(ステートレス)になります(ステートの転送は許可されません)。
  • 制御依存パスで明示的に制約されていない限り、すべてのステージはデフォルトで任意の数(多重度)で同時に実行できます。

免責事項:ここで使用されている用語の一部は、不完全であるか正しくない場合があります。修正は歓迎です。

3
rwong