質問

複数のプロデューサー、単一のコンシューマーモデル(複数のスレッドが単一のファイルライタースレッドにメッセージを送信する)を持つアプリケーションを作成しています。

各プロデューサスレッドには2つのキューがあり、1つは書き込み用で、もう1つはコンシューマ用に読み取り用です。コンシューマスレッドのすべてのループは、各プロデューサを反復処理し、そのプロデューサのミューテックスをロックし、キューをスワップし、ロックを解除し、プロデューサが使用しなくなったキューから書き込みます。

コンシューマスレッドのループでは、すべてのプロデューサスレッドを処理した後、指定された時間だけスリープします。すぐに気づいたのは、1つのプロデューサースレッドから2に移動したときに、プロデューサーがキューに何かを書き込んでリターンする平均時間が劇的に(5倍)増加したことです。 out-10のプロデューサーと15のプロデューサーでかかる時間に大きな違いはありません。これはおそらく、処理するプロデューサーが多いほど、プロデューサースレッドのミューテックスの競合が少ないためです。

残念ながら、<!> lt; 5プロデューサーはアプリケーションのかなり一般的なシナリオであり、プロデューサーの数に関係なく適切なパフォーマンスが得られるようにスリープ時間を最適化したいです。スリープ時間を長くすると、プロデューサー数が少ない場合はパフォーマンスが向上しますが、プロデューサー数が多い場合はパフォーマンスが低下することに気付きました。

他の誰かがこれに遭遇しましたか?もしそうなら、あなたの解決策は何でしたか?スレッド数でスリープ時間をスケーリングしようとしましたが、それはややマシン固有でかなり試行錯誤のようです。

役に立ちましたか?

解決

プロデューサーの数に基づいてスリープ時間を選択したり、動的なスキームに基づいてスリープ時間を調整することもできます。消費者が目覚めて仕事がない場合は、スリープ時間を2倍にします。それ以外の場合は半分にします。ただし、スリープ時間を最小値と最大値に制限します。

より根本的な問題を紙に書き出す方法。スリープとポーリングは簡単に正しい方法であり、利用できる唯一の方法である場合もありますが、多くの欠点があり、<!> quot; right <!> quotではありません。方法。

セマフォを追加することにより、正しい方向に進むことができます。セマフォは、プロデューサがアイテムをキューに追加するたびに増加し、コンシューマがキュー内のアイテムを処理するときに減少します。消費者は、処理するアイテムがある場合にのみ起動し、すぐに起動します。

キューのポーリングは依然として問題になる可能性があります。アイテムがあるキューを参照する新しいキューを追加できます。しかし、プロデューサーごとのキューではなく、コンシューマーが処理する単一のキューがない理由については疑問が生じます。他のすべてが同等であることは、最良のアプローチのように聞こえます。

他のヒント

寝る代わりに、消費者は生産者によって合図された条件でブロックすることをお勧めします。 posix準拠のシステムでは、pthread_condで動作させることができます。プロデューサーごとに1つのpthread_cond_tの配列を作成し、それらの間で共有される追加の配列を作成します。プロデューサーは最初に個々の条件変数を通知し、次に共有変数を通知します。コンシューマは共有条件で待機し、配列の要素を繰り返し処理し、配列の各要素でpthread_cond_timed_wait()を実行します(pthread_get_expiration_np()を使用して<!> quot; now <!> quotの絶対時間を取得します。 )。待機が0を返す場合、そのプロデューサーはデータを書き込んでいます。コンシューマは、再度待機する前に条件変数を再初期化する必要があります。

ブロッキング待機を使用することにより、コンシューマーがプロデューサーを不必要にロックアウトする時間を最小限に抑えることができます。前の回答で述べたように、セマフォを使用してこの作業を行うこともできます。私の意見では、セマフォは条件に比べてセマンティクスが単純化されていますが、コンシューマループの各パスで処理されたプロデューサごとに、共有セマフォを1つずつ減らすように注意する必要があります。条件変数には、シグナルが送信された後に再初期化すると、基本的にブールセマフォのように使用できるという利点があります。

プログラミングに使用する言語のブロッキングキューの実装を見つけてみてください。プロデューサーとコンシューマーの数に関係なく、キューは1つしかありません。

私には、スリープまたは実際の作業のいずれかで、コンシューマスレッドを他の場所でビジー状態にすることによって、誤ってバッファリングを導入しているように思えます。 (バッファとして機能するキュー)おそらく、プロデューサ側でいくつかの単純なバッファリングを行うと、競合が軽減されます。

システムはプロデューサーとコンシューマー間のロック競合に非常に敏感であるようですが、なぜこのような単純なスワップ操作が実行統計に表示されるのに十分なCPU時間を占有するのか困惑しています。

コードを表示できますか?

編集:作業がない場合でも、ロックを取得してキューを交換している可能性がありますか?

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top