0

私のアプリケーションには次のワークフローがあります。システム内で何かを検索したいユーザー (通常は同時に 5 ~ 10 人) からの X 要求が存在する可能性があります (各要求は別のスレッドで処理されます)。

各検索は並行して処理できます (現在実装中です)。これらのタスクは CPU を集中的に使用しないため、ここではスレッド/CPU 使用率は実際には問題ではありません。データベースがボトルネックです。

現在、検索メカニズム専用の別の DB 接続プールをセットアップしています。最大プール サイズは 10 に設定されています。それはそれほど多くはないことはわかっていますが、それ以上に設定することはできません。今、検索ごとに (ユーザーごとに) スレッド プールを設定する方法を見つけようとしています。

各要求 (スレッド) は個別のスレッド プールを生成します (このプールでは、各スレッドが特定のユーザーの検索の一部を処理します)。このスレッド プールのサイズを固定サイズ (たとえば 4) に設定すると、たとえば 10 人のユーザーが一度に「検索」ボタンを押した場合、それぞれ 4 つのスレッド = 40 のスレッドで 10 のスレッド プールが生成され、スレッドは 10 しかないため、非常に問題になります。プール内のデータベース接続?一部のスレッドは単にアイドル状態になり、残りのスレッドはプールへの接続を取得するために競合すると思いますが、それは本当に大きな問題になるでしょうか?

はいの場合、最善の行動方針は次のとおりです。

  1. 新しいものを作成し、それに応じてその(この新しいプールの)最大スレッドプールサイズを調整するときに、すでに存在するスレッドプールの数を確認します(それぞれ4つのスレッドを持つ2つのプールがすでにあるとします。新しいプールは、最大スレッドが2に設定されて作成されますさらに新しいプールでは、最大スレッドが 1 つだけと言えます)。これは、次の各ユーザーの検索が大幅に遅くなることを意味します。
  2. 同じ最大スレッド プール サイズ (つまり 4) でスレッド プールを作成しますが、アプリケーション内のスレッド数を動的にチェックし、それに応じて maxThreadPoolSize のサイズを変更する独自のスレッド プールを実装します (この場合、すべてのスレッド プール、2 つの古いプールそして新しいものは、3スレッドとしましょう)に縮小されます)。これには、各スレッド プールが、アプリケーション内のすべてのスレッド プールに関する情報を含む共有オブジェクトにアクセスする必要があります。
  3. 他の何か?

編集: すべてのコメント/回答に感謝します。リクエストごとにスレッド プールが必要な理由を明確にするために、1 人のユーザーがスレッド プール全体を使い切らないようにしました。フローはまさに次のとおりです。ユーザーが「検索」をクリックすると、オブジェクトのリストが生成され (このリストは 1 アイテムから数千までの範囲)、各アイテムに対して DB ルックアップが実行されます。現在、すべてが順次実行されています。変更後、各タスクは 1 つのルックアップを処理します (DB での検索は非常に遅いため、非常に大きなブーストが得られます。DB の微調整を試みることができることはわかっていますが、私はそれを担当していません)。

問題は、私 User1 が来て、生成された X 千個のアイテムに対して非常に一般的な検索を実行すると、数分 (またはそれ以上) かかる可能性があることです。そのため、1 人のユーザーから executor で何千ものタスクを実行できます。次に、最大 10 個のスレッド (接続プールと同じ数) の共有スレッド プールがある場合、この要求はスレッド プールのキューに入れられます。ここで User2 が来て検索を実行すると、User1 の検索が同じキューに入れられるため、User1 の検索が完了するまで待つ必要があります。これは、リクエストごとのスレッド プールで回避したい状況です。

各計算には最大数秒かかる可能性があるため、コンテキストの切り替えはそれほど頻繁には発生しないため、それほど恐れていません。

現在、各ユーザースレッドがデータを送信する共有スレッドプールとマネージャーについて考えています。そのマネージャーは、アイドルスレッドがあるときはいつでもそれをスレッドプールに送信します。このようにして、それ (マネージャー) を実装して、さまざまなユーザーからタスクを送信することができました (つまり、1 人のユーザーがスレッド プールを支配することはありません)。

このようなアプローチで私が目にする問題は、すべてのタスクがマネージャーによって処理され、何らかの方法で結果を送信することを「親スレッド」(ユーザー要求を意味する) に通知する必要があることです。

4

1 に答える 1

1

最新のプロセッサは何百ものスレッドを問題なく簡単に処理できますが、@PeterLawrey が示唆しているように、設計には何か奇妙な点があります。あなたが言ったように、操作の計算コストが高くない場合、スレッド数が非常に多いと、コストのかかるコンテキストスイッチが多数発生し、パフォーマンスが低下します。

追加の複雑さは、接続プールがアプリケーションごとであるのに対し、リクエストごとにスレッドプールが必要であるという事実から生じます。

  • リクエストごとにスレッドプールがある場合、新しいリクエストを受け取るたびにそれを作成して破棄する必要があります
  • 何兆ものスレッドと 100000 ドルの予算を持つスーパー コンピューターがどのようなものであっても、有用な作業を行うスレッドは 10 個以下です。

直感的に、問題はリクエストごとにスレッドプールが必要であることがわかりますが、理想的な解決策は、リクエスト間でスレッドプールを共有し、スレッドの数を接続プールのサイズと同じにすることです。これにより、スレッドの再利用が最大化されます。

また、1 つの要求がすべてのコンピューティング パワーを占有することを避けたい場合は、誰が追加の作業をスケジュールする権利を持つかを決定するレイヤーを追加することをお勧めします。考えているリクエストごとのスレッドプールソリューションでは、スケジューラにそれをさせていましたが、アルゴリズムを制御しないため、これは良い考えではありません。

代わりに、独自の「公正なアルゴリズム」を実装できます。たとえば、チャンクの数が少ないアイテムが一番上に移動する PriorityBlockingQueue や、スケジュールするジョブのリストと既に持っているジョブのリストをユーザーごとに保存する ConcurrentHashMap を使用できます。返されたなど。

于 2012-08-09T13:39:27.687 に答える