プログラミングにおけるスレッドの適切な使用とは何ですか?


13

多くのプログラムがプロセスごとに最大100を使用する一方で、プロセッサごとに1つのスレッドのみを使用することを推奨することを聞くのはうんざりです!例えば、いくつかの一般的なプログラムを取ります

vb.net ide uses about 25 thread when not debugging
System uses about 100
chrome uses about 19
Avira uses more than about 50

スレッド関連の質問を投稿するたびに、プロセッサごとに複数のスレッドを使用するべきではないことをほぼ毎回思い出し、上記のすべてのプログラムは単一プロセッサのシステムで台無しになっています。


7
その推奨事項は広くすることです。プロセッサごとに1つのスレッドという制限は、計算が制限されたアプリケーションにのみ適しています。ネットワークトラフィック、ディスクアクセス、またはRAMであっても、ほとんどのプログラムはIOにバインドされています。そのため、Webサーバー、データベースなどには、プロセッサコアよりもはるかに多くのスレッドを持つスレッドプールがあります。
キリアンフォス

2
「ほぼ毎回、プロセッサごとに複数のスレッドを使用するべきではないことを思い出します」リンクや例を投稿できますか? ほぼ毎回
S.Lott

2
「...プロセスごとに1つのスレッドのみを使用することを推奨しています。」これらの人々は誰ですか?暗黒時代以降、スケジューリングは大幅に進歩しました。
ラインヘンリヒズ

2
プロセスごとに複数のUIスレッドを使用しないでください。
-SLaks

3
@ビリーONeal、あなたの編集は質問を無意味にしました
SKロジック

回答:


22

プロセッサごとに1つのスレッドのみを使用する必要があります。

おそらくHPCで最大限の効率を求めますが、それ以外は今日聞いた中で最も愚かなことです!

プログラムの設計に適切なスレッド数を使用し、それでも許容可能なパフォーマンスを提供する必要があります。

Webサーバーの場合、着信接続ごとにスレッドを起動するのが妥当かもしれません(ただし、非常に負荷の高いサーバーにはより良い方法があります)。

ideの場合、独自のスレッドで実行される各ツールは不合理ではありません。.Net IDEについて報告されるスレッドの多くは、ロギングやI / Oタスクが独自のスレッドで開始されるため、ブロックを解除しないで続行できると思われます。


9
今、あなたは今まで聞いた中で最も愚かなことは何だろうと思いました!
マイケルK

3
@Michael-私は学部生を教え、防衛契約に取り組んできました-あなたは私が聞いた最も愚かなことを信じないでしょう!
マーティンベケット

1
TheDailyWTF.comでそれらを見たことがありますか?
FrustratedWithFormsDesigner

私は今それらを本当に見つけることができませんが、このリンクを見てくださいsocial.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/…-
スミス

2
持っているほとんどのアプリケーションに割り当てられたプロセッサごとにCPUバウンドスレッド。IOにバインドされたスレッドは(それらが消費するメモリ以外の)大きな問題ではなく、アプリはシステムのCPUのサブセットのみを使用するように制限できることを覚えておくことが重要です。結局のところ、それは(通常)ユーザー/管理者のコンピューターであり、プログラマーのコンピューターではありません。
ドナルドフェロー

2

コアごとに1スレッドのアドバイスは、目的が並列実行の速度である場合に適用されます。

まったく異なる正当な理由は、予測不可能なイベントに応答する必要がある場合のコードの単純さです。そのため、プログラムが100個のソケットでリッスンする必要があり、各ソケットに十分な注意を払うように見える場合、それはスレッド化に最適です。別の例はUIで、1つのスレッドがUIイベントを処理し、別のスレッドがバックグラウンド処理を行います。


1
IOバウンド処理は、イベントソースごとに1つのスレッドとして実行できます。または、複数のイベントソースを単一のスレッドに多重化できます。多重化コードは通常、より複雑で効率的です。
ドナルドフェロー

2

計算ごとに1つのスレッドが必要であり、他の計算とは異なる速度で進行できます。

大量の作業ブロックを伴う並列CPUバインド計算の場合、通常はCPUごとに1つのスレッドが必要です。すべてのスレッドがビジーになると、多くのスレッドが役に立たず、スケジューラのオーバーヘッドが発生するだけです。作業ブロックが時間的に不規則なサイズを持っている場合、または実行時に動的に生成される場合(多くの場合、処理する大きな複雑なデータ構造がある場合に発生します)、それらのブロックを多数のスレッドにアタッチすることができます。すべてのCPUをビジー状態に保つために、作業ブロックの完了時に選択するように設定します。

I / Oバウンド計算の場合、通常、独立したI / O "チャネル"ごとに1つのスレッドが必要です。異なる速度で通信し、チャネルでブロックされるスレッドは、他のスレッドの進行を妨げません。


このスタイルのスレッドは、奇妙に設計されたプログラムにつながる可能性があることに注意してください。DBテーブルからレコードを読み取るスレッド、変換されたレコードをソケットに書き込むスレッド、それらのソケット書き込みに対する応答を読み取るスレッド(順不同で戻ってきた)を備えた4スレッドプログラムを見てきましたおよび非同期)、および応答で元のDBレコードを変更するスレッド。直感的でないエラー状態が発生しました。
ブルースエディガー

一つの見方は、このスタイルは奇妙なプログラムを生み出すということです。別の見方では、これはプログラムが持つべき自然なスタイルです。「直感的でない」エラー条件に関するダンノ。多くのことが起こっており、そのうちの1つがエラーを受け取った場合、非同期計算全体に適切に伝播されるようにすることは多くの言語で問題になります[愚かなことに、Java例外はスレッド境界で定義されていません]プログラムスタイルの問題。(PARLANSEプログラミング言語[私の略歴を参照]はスレッド境界を越えて例外をきれいに処理するため、これを正しく行うことができます。)
アイラバクスター

1

スレッドの経験則では、コンピューターで使用可能な各「実行ユニット」に対して少なくとも1つの「アクティブ」(CPU時間を指定するとすぐにコマンドを実行できる)ワーカースレッドが必要です。「実行ユニット」は1つの論理命令プロセッサであるため、クアッドチップ、クアッドコアXeonハイパースレッドサーバーには32 EU(4チップ、チップあたり4コア、各ハイパースレッド)があります。あなたの平均的なCore i7には8があります。

スレッドが常に実行状態にある場合、EUごとに1つのスレッドがCPUの電力を最大限に使用します。スレッドは、キャッシュされていないメモリ、ハードディスク、ネットワークポートなどにアクセスする必要があり、実行するためにアクティブなCPUの注意を必要としないため、これはほとんどありません。したがって、より多くのスレッドを待ち行列に入れて移動することで、全体的な効率をさらに高めることができます。これにはコストがかかります。CPUがスレッドを切り替えるとき、スレッドのレジスタ、実行ポインター、および通常EUの最も内側の作業に保持され、非常に高速にアクセスされる他の状態情報をキャッシュし、そのCPUチップ内の他のEUがそれを取得できるようにする必要があります。また、OS内のスレッドが切り替えられるスレッドを決定する必要があります。最後に、EUがスレッドを切り替えると、ほとんどのプロセッサアーキテクチャで使用されているパイプライン処理のパフォーマンス向上が失われます。スレッドを切り替える前にパイプラインをフラッシュする必要があります。しかし、これらすべては、ハードドライブやRAMが情報を返すのを単に待つよりも、平均してはるかに短い時間で済むため、コストに見合うだけの価値があります。

ただし、一般に、「アクティブ」スレッドの数がEUの2倍を超えると、OSはEUのスレッドスケジューリングに多くの時間を費やし始め、EUは実際にアクティブスレッドの実行に費やす時間よりも多くの時間を切り替えますプログラムの。これが規模の不経済のポイントです。この時点で追加のスレッドを追加すると、マルチスレッドアルゴリズムの実行に実際に時間がかかります。

したがって、全体的には、コンピューター上のEUの数と少なくとも同じ数のスレッドをプログラム内に維持したいが、待機またはスリープしていないその数の2倍を超えないようにする必要があります。


Nがスレッドの数であり、Uがユニットの数である場合、OPは「N = U」ルールを疑問視しました。「U <= N <= 2 U」ルールに従ってリラックスしています。さらに少し進んで、「合理的に小さい」定数(プログラマーに知られている)cの「N <= c U」は許容できると言います(ベンチマークが妥当なパフォーマンスを示す場合)。スレッドの数が潜在的に無制限の数にまで拡大する可能性があるかどうかは非常に心配です。
5gon12eder

1

次の場合に1つのスレッドを使用する必要があります。

忙しくする必要がある各プロセッサ。

ブロッキングなしで実行できない各I / Oは、同時に有効に保留できます。(たとえば、ローカルディスクから読み取ります。)

専用スレッドを必要とする各タスク。たとえば、非ブロッキングインターフェイスのないライブラリを呼び出したり、非ブロッキングインターフェイスが適切でない場合。これには、システムクロックの監視、タイマーの起動などのタスクが含まれます。

ページフォールトなどの予期しないブロックから保護するためのいくつかの追加。

クリティカルでないコードなど、最適化する価値のない予想されるブロックから保護するためのいくつかの追加。(たとえば、ごくまれにDNSリクエストを行う必要がある場合、DNSリクエストを非同期に行う価値はおそらくないでしょう。いくつかの追加のスレッドを作成して、作業を楽にするだけです。)

「プロセッサごとに1つのスレッド」ルールに従う場合、すべてのコードのパフォーマンスが重要になります。何らかの理由でブロックするコードは、プロセスがそのプロセッサを使用できないことを意味します。それは、正当な理由もなくプログラミングをより難しくします。


0

プロセスとスレッドを生成して、単一のプログラムでマルチコア\マルチプロセッサシステムを利用できるようにすることができます。

または、通常、さらなる実行をブロックするイベントをポーリングするルーチンを持つことができます。CPUをポーリングと結び付けるのではなく、代わりに、適切なイベントが起動するまでアイドル状態にあるスレッドを作成できます。この方法は、WebサーバーおよびGUIイベントキューで非常に一般的に使用されています。ほとんどのプログラムは、すべてのスレッドがアクセスできる何らかの種類の中央データストア(プログラムの実行コードであっても)を必要とするため、プロセス上のスレッドを使用するのはそのためです。


0

あなたが言及するアプリは、これらの数十のスレッドすべてを同時に実行することはめったにありません。彼らのほとんどはスレッドプールにいるのでそこに座っています。アプリはさまざまなタスクをキューに送信します。キューはスレッドプール内のスレッドによって削除されます。

プールのサイズが大きいのはなぜですか?なぜなら、多くの場合、スレッドはディスク、ネットワーク、ユーザー、その他のスレッドなどの他のリソースを待たなければならないからです。ただし、プールのサイズを適切に調整するのは難しいです。スレッドが少なすぎると、何かを待っている間にプロセッサが完全に使用されないため、パフォーマンスが低下します。スレッドが多すぎると、スレッドを切り替えるためにパフォーマンスが低下します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.