4

私は比較的 perl に不慣れで、perl でのスレッド化についてはさらに新しいです。3 つの異なるソースから入力を受け取る perl スクリプトがあります。(2 つの LDAP クエリと、常にそこにあるとは限らないファイル) 一部の部分は他の部分よりも時間がかかる可能性があるため、スレッドとキューを使用することにしました。開発中、スクリプトの個々のコンポーネントのテストは非常にうまく機能しましたが、すべてをまとめた後はパフォーマンスが低下したようです。

基本的な構造は、この 2 つのスレッドです:(ファイルの読み取りまたは AD エントリの読み取り) -> Queue1 -> 2 つのスレッド:(データのスクラブ) -> Queue2 -> 3-4 スレッド (既存のローカル LDAP エントリと比較)。いくつかのスレッドが統計をメイン スクリプトに報告し、すべてのスレッドが完了すると、その実行のすべての統計とステータスが記載された電子メールが送信されます。

私は dequeue_nb を使用していますが、それは役立つと思いましたが、うまくいきませんでした。

パフォーマンス ヒットは待ち行列に入っているようです。パフォーマンスを改善するためのヒントを探しているときに、perl スレッドは良くなく、coro、POE、Anyevent、IO:async などを使用するといういくつかの記事に出くわしました。

これは「イベント」の問題のようには見えないので、AnyEvent や POE が私が見ているものから通り抜ける方法になるとは思いませんでした.coros は一度に 1 つの CPU しか使用しないようですので、よくわかりませんこれはどちらでも機能します。組み合わせて使おうと思ったのですが、頭が痛くなりました。私のスクリプトを修正/トラブルシューティングする方法、または他のモジュールのいずれかを実装する方法についての提案はありますか?

4

2 に答える 2

5

並列処理の問題は同期です。それはパフォーマンスキラーであり、悪いことであり、できれば避けるべきです。

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 つのステージのスレッドの最大の実用的な数と見なすことができます。それを超えると、メモリ ペナルティが発生するだけで、スピードアップはありません。ステージが入力を提供されるよりも速く処理できる場合、パフォーマンスの飽和点に早く到達する可能性があります。

于 2012-07-30T20:17:31.887 に答える
0

キューに入れるデータの種類は何ですか? 私の知る限り、単純なデータは複雑な構造よりも安価です。これは、複製して少なくとも 2 回コピーする必要があるためです。より高速なキューの実装を作成することを計画しています (ほとんどの作業は実際には既に行われています) が、まだ公開していません。

于 2012-07-30T21:51:06.813 に答える