スレッドの数は多すぎますか?


312

私はサーバーを書いていて、リクエストを受け取ったときにそれぞれのアクションを別々のスレッドに送ります。ほとんどすべてのリクエストがデータベースクエリを作成するため、これを行います。私はスレッドプールライブラリを使用して、スレッドの構築/破棄を削減しています。

私の質問は次のとおりです。これらのようなI / Oスレッドの適切なカットオフポイントは何ですか?おおよその概算であることは知っていますが、何百もの話をしていますか?何千?

このカットオフがどうなるかを理解するにはどうすればよいですか?


編集:

回答ありがとうございます。スレッド数の上限を調べるためにテストする必要があるようです。しかし、問題は、私がその上限に達したことをどのようにして知ることができるかです。正確に何を測定すべきですか?


1
@ryeguy:ここで重要なのは、最初からパフォーマンスの問題がない場合は、スレッドプールに最大値を設定してはならないということです。スレッドプールを〜100スレッドに制限するというアドバイスのほとんどはばかげています。ほとんどのスレッドプールには/ way /より多くのスレッドがあり、問題はありません。
GEOCHET 2009年

ryeguy、何を測定すべきかについて、以下の私の答えに加えて参照してください。
paxdiablo 2009年

Pythonは本質的にマルチスレッド対応ではないことを忘れないでください。どの時点でも、単一のバイトコードオペコードが実行されています。これは、Pythonがグローバルインタープリターロックを採用しているためです。
ASk 2009年

1
@ジェイ・デイ:天井にぶつかった瞬間は、パフォーマンスが落ち始めたときだと思います。
ninjalj 2010年

6
@GEOCHET 「ここで重要なのは、スレッドプールに最大値を設定してはならないことです」うーん...何と言いますか?固定サイズのスレッドプールには、適切な低下とスケーラビリティという利点があります。たとえば、ネットワーク設定で、クライアント接続に基づいて新しいスレッドを生成している場合、プールサイズが固定されていないと、サーバーが処理できるスレッドの数と、接続されているすべてのクライアントを学習するという非常に現実的な危険があります(難しい方法)苦しむでしょう。固定サイズのプールは、サーバーが噛む以上に噛み付こうとしないようにすることで、パイプバルブのように機能します。
b1nary.atr0phy 2015

回答:


206

一部の人々は、2つのスレッドが多すぎると言います-私はそのキャンプに完全ではありません:-)

ここに私のアドバイスがあります:測定して、推測しないでください。1つの提案は、それを構成可能にして、最初に100に設定してから、ソフトウェアを実際にリリースして何が起こるかを監視することです。

スレッドの使用率が3に達すると、100は多すぎます。1日の大半が100のままである場合は、最大200まで上げて、何が起こるかを確認します。

あなたは可能性があり、実際に自分自身の使用状況を監視し、それが起動しますが、それはおそらく行き過ぎだ次回のために設定を調整し、あなたのコードを持っています。


説明と詳細については:

私はあなた自身のスレッドプーリングサブシステムをローリングすることを主張していません、必ずあなたが持っているものを使ってください。しかし、スレッドの適切なカットオフポイントについて質問していたので、スレッドプールの実装には、作成されるスレッドの最大数を制限する機能があると思います(これは良いことです)。

私はスレッドとデータベース接続プールのコードを記述しましたが、それらには次の機能があります(パフォーマンスに不可欠であると私は信じています)。

  • アクティブなスレッドの最小数。
  • スレッドの最大数。
  • しばらく使用されていないスレッドをシャットダウンする。

1つ目は、スレッドプールクライアントの観点から最小パフォーマンスのベースラインを設定します(この数のスレッドは常に使用可能です)。2番目は、アクティブなスレッドによるリソース使用量に制限を設定します。3番目は、リソースの使用を最小限に抑えるために、静かな時間にベースラインに戻ります。

未使用のスレッドがあるリソース使用量(A)と、作業を行うのに十分なスレッドがないリソース使用量(B)のバランスをとる必要があります。

(A)は、通常、メモリ使用量(スタックなど)です。これは、処理を行わないスレッドがCPUの多くを使用しないためです。(B)スレッドが使用可能になるのを待つ必要があるため、リクエストが到着すると、一般にリクエストの処理が遅れます。

それがあなたが測定する理由です。述べたように、スレッドの大部分はデータベースからの応答を待っているため、実行されません。許可するスレッドの数に影響を与える2つの要因があります。

1つ目は、使用可能なDB接続の数です。これは、DBMSで増やすことができない場合、ハードリミットになる可能性があります。この場合、DBMSが無制限の数の接続を取ることができると想定します(理想的には、それも測定する必要があります)。

次に、スレッドの数は、過去の使用状況によって異なります。実行する必要がある最小値は、これまでに実行したことがある最小値+ A%で、絶対最小値は(たとえば、Aのように構成可能にする)5。

スレッドの最大数は、過去の最大値+ B%にする必要があります。

また、行動の変化を監視する必要があります。なんらかの理由で、使用率が100%になるまでかなりの時間(クライアントのパフォーマンスに影響を与えるため)になる場合は、許容される最大値を上げて、再びB%高くなるようにする必要があります。


「正確に何を測ればいいの?」に応えて 質問:

特に測定する必要があるのは、負荷がかかっている状態で同時に使用されている(たとえば、DB呼び出しからの戻りを待機している)スレッドの最大量です。次に、たとえば 10%の安全率を追加します(他のポスターは私の例を固定された推奨事項と見なしているようなので、強調します)。

さらに、これは本番環境で調整する必要があります。事前に見積もりを取得することは問題ありませんが、どのプロダクションがあなたのやり方を投げるのかわかりません(そのため、これらすべてが実行時に構成可能でなければなりません)。これは、着信するクライアントコールが予期せず2倍になるなどの状況を把握するためです。


着信要求でスレッドが生成される場合、thread-usageはサービスされていない要求の数を反映します。これから「最適な」数を決定する方法はありません。実際、スレッドが増えるとリソースの競合が発生し、アクティブなスレッドの数が増加します。
アンドリューグラント

@Andrew、スレッドの作成には時間がかかり、履歴データ[+ N%]に基づいて最適な数を決定できます(したがって、推測ではありません)。さらに、スレッドが増えると、シグナル/セマフォを待たずに、作業を行っているときにのみリソースの競合が発生します。
paxdiablo 2009年

スレッドプールの使用時にパフォーマンスの問題を引き起こす「スレッド作成」に関するこのデータはどこにありますか?優れたスレッドプールは、タスク間でスレッドを作成および破棄することにはなりません。
GEOCHET 2009年

@Paxすべてのスレッドが同じセマフォでDBクエリの実行を待機している場合、それがまさに競合の定義です。また、セマフォを待機している場合、スレッドにコストがかからないというのも事実ではありません。
Andrew Grant、

1
@Andrew、なぜDBクエリをセマフォブロックするのかわかりません。まともなDBであれば、多数のスレッドが応答を待って同時アクセスを許可します。また、セマフォがブロックされている間、スレッドは実行時間を費やさないでください。セマフォが解放されるまで、スレッドはブロックされたキューに留まる必要があります。
paxdiablo 2009年

36

この質問はかなり徹底的に議論されており、すべての回答を読む機会がありませんでした。ただし、特定のシステムで平和的に共存できる同時スレッドの数の上限を見ながら、考慮すべき点がいくつかあります。

  1. スレッドスタックサイズ:Linuxでは、デフォルトのスレッドスタックサイズは8MBです(ulimit -aを使用して調べることができます)。
  2. 特定のOSバリアントがサポートする最大仮想メモリ。Linux Kernel 2.4は、2 GBのメモリアドレス空間をサポートしています。カーネル2.6では、私は少し大きくなりました(3GB)
  3. [1]は、サポートされている特定の最大VMあたりのスレッドの最大数の計算を示しています。2.4では、スレッド数は約255になります。2.6の場合、数値は少し大きくなります。
  4. どのようなカーネルスケジューラがありますか。Linux 2.4カーネルスケジューラと2.6を比較すると、後者はシステムに存在するタスクの数に依存しないO(1)スケジューリングを提供しますが、最初のタスクはO(n)です。したがって、カーネルスケジュールのSMP機能も、システム内の持続可能なスレッドの最大数に影響します。

これで、スタックサイズを調整してより多くのスレッドを組み込むことができますが、スレッド管理(作成/破棄およびスケジューリング)のオーバーヘッドを考慮する必要があります。特定のプロセスだけでなく特定のスレッドにもCPUアフィニティを適用して、それらを特定のCPUに結び付け、CPU間のスレッド移行のオーバーヘッドを回避し、コールドキャッシュの問題を回避できます。

彼/彼女の望みどおりに何千ものスレッドを作成することができますが、LinuxがVMを使い果たすと、ランダムにプロセス(したがってスレッド)を強制終了します。これは、ユーティリティプロファイルがいっぱいにならないようにするためです。(ユーティリティ関数は、一定量のリソースに対するシステム全体のユーティリティについて通知します。この場合のリソースが一定の場合、CPUサイクルとメモリにより、ユーティリティ曲線はタスクの数が増えるにつれてフラットになります)。

Windowsカーネルスケジューラも、リソースの過剰使用に対処するためにこの種のことを行うと確信しています

[1] http://adywicaksono.wordpress.com/2007/07/10/i-can-not-create-more-than-255-threads-on-linux-what-is-the-solutions/


17

スレッドがあらゆる種類のリソース集約型の作業(CPU /ディスク)を実行している場合、1つまたは2つを超えるメリットはめったになく、多すぎるとパフォーマンスがすぐに低下します。

「最良の場合」は、最初のスレッドが完了するまで後のスレッドが停止するか、競合の少ないリソースでオーバーヘッドの少ないブロックが発生するスレッドです。最悪のケースは、キャッシュ/ディスク/ネットワークのスラッシングを開始し、全体的なスループットがフロアを通過して低下することです。

良い解決策は、リクエストをプールに入れ、それをスレッドプールからワーカースレッドにディスパッチすることです(そして、はい、継続的なスレッドの作成/破棄を回避することは素晴らしい最初のステップです)。

このプール内のアクティブなスレッドの数は、プロファイリングの結果、実行中のハードウェア、およびマシンで発生している可能性のあるその他の事柄に基づいて調整およびスケーリングできます。


はい。キューまたはリクエストのプールと組み合わせて使用​​する必要があります。
アンドリューグラント

2
@アンドリュー:なぜ?要求を受信するたびに、スレッドプールにタスクを追加する必要があります。使用可能なスレッドがある場合、タスクにスレッドを割り当てるのはスレッドプール次第です。
GEOCHET 2009年

では、何百ものリクエストがスレッドから出てきたときにどうしますか?さらに作成しますか?ブロック?エラーを返しますか?要求を必要なだけ大きくできるプールに配置し、スレッドが解放されたら、これらのキューに入れられた要求をスレッドプールに送ります。
アンドリューグラント

「いくつかのタスクを実行するためにいくつかのスレッドが作成され、通常はキューに編成されます。通常、スレッドよりも多くのタスクがあります。スレッドがタスクを完了するとすぐに、キューから次のタスクを要求しますすべてのタスクが完了するまで。」
GEOCHET 2009年

@Andrew:OPが使用しているPythonスレッドプールはわかりませんが、この機能の実際の例が必要な場合は、msdn.microsoft.com
en

10

覚えておくべきことの1つは、Python(少なくともCベースのバージョン)は、マルチコアマシンのパフォーマンスに大きな影響を与える可能性があるグローバルインタープリターロックと呼ばれるものを使用することです。

マルチスレッドPythonを最大限に活用する必要がある場合は、Jythonなどの使用を検討してください。


4
これを読んだ後、3つのスレッドでEratosthenesタスクのふるいを実行してみました。案の定、実際には、同じタスクを単一のスレッドで実行するよりも50%遅くなりました。ヘッドアップをありがとう。2つのCPUが割り当てられた仮想マシンでEclipse Pydevを実行していました。次に、いくつかのデータベース呼び出しを含むシナリオを試します。
Don Kirkby、

3
タスクには2つのタイプ(少なくとも)があります。CPUバウンド(例:画像処理)とI / Oバウンド(例:ネットワークからのダウンロード)です。明らかに、GILの「問題」はI / Oバウンドタスクにあまり影響を与えません。タスクがCPUバウンドの場合、マルチスレッドではなくマルチプロセッシングを検討する必要があります。
iutinvg 2016年

1
はい、ネットワークioがたくさんある場合、pythonスレッドは改善されました。スレッドに変更して、通常のコードよりも10 *速くなりました...
tyan

8

パックスが正しく言ったように、測定して、推測しないでくださいDNSwitnessとその結果に対して私がしたことは驚くべきことでした。スレッドの理想的な数は思ったよりもはるかに多く、最速の結果を得るために15,000スレッドのようなものでした。

もちろん、それは多くの事柄に依存します。そのため、自分で測定する必要があります。

Combien de fils d'executionの完全な対策(フランス語のみ)


1
15,000?それは私が期待していたよりも少し高いです。それでも、それがあなたが得たものであり、それがあなたが得たものである場合、私はそれについて議論することはできません。
paxdiablo 2009年

2
この特定のアプリケーションでは、ほとんどのスレッドがDNSサーバーからの応答を待っているだけです。つまり、並列時間が多ければ多いほど、実時間ではより良いものになります。
bortzmeyer、2009年

18
外部I / Oでブロックされている15000のスレッドがある場合、より優れたソリューションは、スレッドが大幅に少ないが非同期モデルであると思います。ここでの経験からお話します。
スティーブ

5

多数のマルチスレッドアプリを多数作成しました。一般に、潜在的なスレッドの数を構成ファイルで指定できます。特定の顧客向けに調整したとき、すべてのCPUコアの使用率がかなり高くなるほど十分に高い数値を設定しましたが、メモリの問題に遭遇するほど高くはありませんでした(これらは32ビットオペレーティングシステムでした)時間)。

言い換えると、CPU、データベーススループット、ディスクスループットなどのボトルネックが発生した場合、スレッドを追加しても全体的なパフォーマンスは向上しません。しかし、そのポイントに達するまで、さらにスレッドを追加してください!

これは、問題のシステムがアプリ専用であることを前提としているため、他のアプリを上手にプレイする(飢えを避ける)必要はありません。


1
スレッドカウントで見た数のいくつかについて言及できますか?それを理解するだけで役に立ちます。ありがとう。
kovac

3

「ビッグアイアン」の答えは通常、限られたリソース(プロセッサ(CPUバウンド)、アーム(I / Oバウンド)など)ごとに1つのスレッドですが、リソースの正しいスレッドに作業をルーティングできる場合にのみ機能しますアクセスされます。

それが不可能な場合は、代替可能リソース(CPU)と非代替可能リソース(アーム)があることを考慮してください。CPUの場合、各スレッドを特定のCPUに割り当てることは重要ではありませんが(キャッシュ管理には役立ちます)、アームの場合、スレッドをアームに割り当てることができない場合は、キューイング理論とアームを保持するための最適な数を取得します忙しい。一般的に、使用するアームに基づいてリクエストをルーティングできない場合は、アームごとに2〜3スレッドを使用するのが適切だと思います。

スレッドに渡される作業単位が合理的にアトミックな作業単位を実行しないと、複雑さが生じます。たとえば、ある時点でスレッドにディスクにアクセスさせ、別の時点でネットワークで待機させることができます。これにより、追加のスレッドが入り込んで有用な作業を実行できる「クラック」の数が増えますが、追加のスレッドが互いのキャッシュなどを汚染してシステムを停止させる可能性も高くなります。

もちろん、これらすべてを糸の「重さ」と比較検討する必要があります。残念ながら、ほとんどのシステムには非常に重いスレッド(そして「軽量スレッド」と呼ばれるものは多くの場合まったくスレッドではない)があるため、ローサイドでエラーを発生させる方がよいでしょう。

実際に私が見たのは、非常に微妙な違いが最適なスレッドの数に大きな違いをもたらす可能性があるということです。特に、キャッシュの問題とロックの競合により、実際の同時実行性が大幅に制限される可能性があります。


2

考慮すべき1つのことは、コードを実行するマシン上に存在するコアの数です。これは、同時に処理できるスレッド数のハード制限を表しています。ただし、あなたのケースのように、スレッドがデータベースによるクエリの実行を頻繁に待機していることが予想される場合は、データベースが処理できる同時クエリの数に基づいてスレッドを調整することをお勧めします。


2
いいえ。スレッドの全体のポイントは(マルチコアおよび複数のプロセッサが普及する前)、1つだけのマシンで複数のプロセッサを持つことを模倣できることです。これが、レスポンシブなユーザーインターフェイス(メインスレッドと補助スレッド)を取得する方法です。
mmr 2009年

1
@mmr:ええと。スレッドの考え方は、I / Oや他のタスクをブロックできるようにすることです。
GEOCHET 2009年

4
私が言ったのは、マシン上のコアの数は、特定の時間に作業を実行できるスレッドの数のハード制限を表すというものでした。これは事実です。もちろん、他のスレッドがI / O操作の完了を待機している可能性があります。この質問では、これは重要な考慮事項です。
2009年

1
とにかく-あなたはPythonでGILを使用しています。同時に実行できるスレッドは1つだけなので、重要なのは応答性とブロック操作だけです。
アブガン2009年

2
+1コンピュータの仕組みを実際に理解するため。@mmr:複数のプロセッサを搭載しているように見える場合と、複数のプロセッサを搭載している場合の違いを理解する必要があります。@リッチB:スレッドプールは、スレッドのコレクションを処理する多くの方法の1つにすぎません。それは良いものですが、確かに唯一のものではありません。
悲しむ

2

これはあなたの質問に対する少しの回避ですが、なぜそれらをプロセスにフォークしないのですか?ネットワーキングについての私の理解(漠然とした昔から、私はネットワークをまったくコーディングしていません)は、各着信接続を個別のプロセスとして処理できるということです。プログラム全体を核攻撃します。


1
Pythonの場合は特に当てはまります。複数のスレッドが並行して実行できる一方で、複数のスレッドは実行できないためです。ただし、コストはかなり高くなります。毎回新しいPythonインタープリターを起動し、各プロセスでDBに接続する必要があります(またはパイプリダイレクトを使用しますが、それには代償が伴います)。
アブガン、2009年

プロセス間の切り替えは、ほとんどの場合、スレッド間の切り替えよりもコストがかかります(一部のレジスターではなくコンテキスト全体の切り替え)。最後に、それはあなたのthreading-libに大きく依存します。質問はスレッド化に関係しているので、プロセスはすでに問題外であると思います。
レオニダス

けっこうだ。他の答えが機能するのではなく、スレッドのみの答えを表示したい場合を除いて、スコアが-2になるのはなぜでしょうか。
mmr 2009年

@mmr:/ thread /プールについての質問だったので、はい、人々はスレッドについての回答を期待しているはずです。
GEOCHET 2009年

プロセスの作成は、起動時に一度行うことができます(つまり、スレッドプールの代わりにプロセスプール)。アプリケーション期間にわたって償却されるため、これはわずかな場合があります。彼らは簡単に情報を共有することはできませんが、マルチCPUで実行できる可能性があるため、この回答は役に立ちます。+1。
paxdiablo 2009年

1

ライギー、私は現在同様のアプリケーションを開発しており、私のスレッド数は15に設定されています。残念ながら20に増やすと、クラッシュします。ですから、はい、これを処理する最良の方法は、現在の構成でスレッドの数Xより多いか少ないかを測定することです。


5
スレッド数を追加しても、アプリがランダムにクラッシュすることはありません。いくつかの理由があります。状況によってはスレッド数が少ない場合でも影響を与える可能性があるため、原因を突き止めるのはよいでしょう。
マシュールンド

-6

ほとんどの場合、スレッドプールでこれを処理できるようにする必要があります。コードを投稿したり、詳細を提供したりすると、スレッドプールのデフォルトの動作が最適ではない理由があるかどうかを確認しやすくなります。

これがどのように機能するかの詳細については、http//en.wikipedia.org/wiki/Thread_pool_patternを参照してください。


1
@Pax:これは、大多数の人が目の前の質問に答える(または理解する)ことを望まなかったのは初めてではありません。私は心配していない。
GEOCHET 2009年

-10

CPUコアと同じ数のスレッドは、私がよく耳にするものです。


5
@リッチ、少なくとも理由を説明してください:-)。この経験則は、すべてのスレッドがCPUにバインドされている場合にのみ適用されます。彼らはそれぞれ1つの「CPU」を取得します。スレッドの多くがI / Oバウンドである場合、通常は「CPU」よりも多くのスレッドを使用することをお勧めします(CPUは、コアなどの実行の物理スレッドに適用されるため、引用されています)。
paxdiablo 2009年

1
@Abgan、私はそれについて確信が持てなかった、多分Pythonが「実際の」OSスレッド(複数のCPUで実行される)を作成するだろうと考えていた。あなたが言っていることが真実である場合(私が疑う理由はありません)、CPUの量には関係がありません。スレッド化は、ほとんどのスレッドが何か(たとえば、DB I / O)を待機している場合にのみ役立ちます。
paxdiablo 2009年

1
@リッチ:(実際の)スレッディングの場合、待機していない複数のスレッドを本当に同時に実行できるため、CPU数には影響があります。1つのCPUで実行されるのは1つだけであり、CPU以外のリソースを待機する他の多くのスレッドを使用することでメリットが得られます。
paxdiablo 2009年

1
@Pax:スレッドプールの概念を理解していないと思います。
GEOCHET 2009年

1
@リッチ、私はスレッドプールをうまく理解しています。私(および他の人)もあなたよりもハードウェアをよく理解しているようです。1つのCPUを使用すると、CPUを待機している他のスレッドがある場合でも、実行できる実行スレッドは1つだけです。2つのCPU、2つを実行できます。すべてのスレッドがCPUを待機している場合、理想的なスレッド数は...に等しい
paxdiablo 2009年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.