並列処理の問題は同期です。それはパフォーマンスキラーであり、悪いことであり、できれば避けるべきです。
OP アーキテクチャ
あなたのアーキテクチャを見てみましょう:
+--------------+--------------+
| Input 1 | Input 2 |
+--------------+--------------+
| QUEUE A |
+--------------+--------------+
| Scrub 1 | Scrub 2 |
+--------------+--------------+
| QUEUE B |
+---------+---------+---------+
| Compare | Compare | Compare |
+---------+---------+---------+
討論
キュー A は 4 つのスレッド間で同期する必要があります。5-6 列の B 列。常に 1 つのスレッドのみが Queue にアクセスできるため、ほとんどの場合、スレッドは待機しており、機能していません!
並列パイプライン アーキテクチャ
多少異なるアーキテクチャは次のようになります。
+-----------+ +-----------+
| Input 1 | | Input 2 |
+-----------+ +-----------+
| QUEUE 1A | | QUEUE 2A |
+-----------+ +-----------+
| Scrub 1 | | Scrub 2 |
+-----------+ +-----------+
| QUEUE 1B | | QUEUE 2B |
+-----+-----+ +-----+-----+
| Cmp | Cmp | | Cmp | Cmp |
+-----+-----+ +-----+-----+
討論
ここで、A Queues は 2 つのスレッドのみに関連付けられ (->より少ない待機)、B Queues は 3 つのみに関連付けられます。このアーキテクチャは、同様の入力サイズ/複雑さに対してより高速に実行する必要があります。入力 2 がかなり短い場合、パイプライン 1 が半分終了する前に、パイプライン 2 全体が実行されます。ただし、パイプラインごとに 1 つのプロセスを使用するよりもはるかに優れています。
芝生のスプリンクラーのアーキテクチャ
概念
さらに優れたアーキテクチャでは、プロセスの出力を複数のキューに分散しようとします。(逆に、スレッドが複数のキューから入力を取得するのは、キューが空の場合に良くありません。)
各キューの書き込みは、異なるキューに移動する必要があります。
+-----------+ +-----------+
| Input 1 | | Input 2 |
+-----------+ +-----------+
| \ / |
+-----------+ +-----------+
| QUEUE 1A | | QUEUE 2A |
+-----------+ +-----------+
| Scrub 1 | | Scrub 2 |
+-----------+ +-----------+
/ | \ \ / / | \
+-------+-------+-------+-------+
| Q. 1B | Q. 2B | Q. 3B | Q. 4B |
+-------+-------+-------+-------+
| Cmp | Cmp | Cmp | Cmp |
+-------+-------+-------+-------+
これにより、各スレッドが同じワークロードを持つようになりますが、すべてのスレッドが同時に終了することは保証できません。
討論
すべてのキューは 3 つのスレッド間で共有されます。問題は、キューへの書き込み時に 2 つのスレッドが互いにブロックすることです。キュー書き込みアクセス間の時間が書き込み期間よりも大幅に長い場合、これは問題にはなりません。それ以外の場合は、2 番目のアーキテクチャを混在させることができます。
したがって、このアーキテクチャが理にかなっている場合は、正確な要件によって異なります。
均等なサイズの入力の場合は遅くなりますが、不規則な入力の場合はパフォーマンスが向上します。
付録
実装について:
どのフレームワークが使用されるかは、アーキテクチャの二次的なものです。テキスト文字列のみを渡す場合は、パイプを使用することを強くお勧めします。Perlのデータ型またはオブジェクトを渡す必要がある場合は、実際のキューを使用することによる追加のオーバーヘッドを受け入れる必要がある可能性があります。共有されていない変数をキューに追加する場合、ディープコピーを作成する必要があります(@Leon Timmermansの回答を参照)。すべての同期オーバーヘッドに。
スケーラビリティについて:
アーキテクチャ 1 と 3 は、スレッド数が固定されていません。この柔軟性を利用して、さまざまな構成のベンチマークを行うことを強くお勧めします。経験則では、nから2nのスレッドを使用する必要があります。ここで、n はプロセッサ (またはハードウェア スレッド) の数です。これは、1 つのステージのスレッドの最大の実用的な数と見なすことができます。それを超えると、メモリ ペナルティが発生するだけで、スピードアップはありません。ステージが入力を提供されるよりも速く処理できる場合、パフォーマンスの飽和点に早く到達する可能性があります。