web-dev-qa-db-ja.com

物事をチェックするためにたくさんループするスレッドを作成することはパフォーマンスへの影響ですか?

これは私がいつも疑問に思っている一般的な質問です。

一般的に、CPUが「while not true ...」ループなどを実行するスレッドを作成するのは集中的ですか?

たとえば、次のようにするとします。

// pseudo-code
new Thread(function() {
    while (!useHasDoneSomething) {
        // do nothing...
    }
    alert("you did something!");
}

つまり、何かが発生するのを待つスレッドで実行されるコードの一部です。

何らかの理由で、これがCPUに圧力をかけると想像します。結局のところ、それは1つの小さなループですが、サイクルが行われた瞬間にループを再実行しています。これは、1ミリ秒に何回もサイクルを繰り返すことを意味しませんか? ...ナノ秒あたり!?

オペレーティングシステムはプログラムとスレッドを「処理」しますよね?しかし、それはまだループを実行することに非常に多くの注意を払っています。 CPUが他に何もする必要がない場合、そのループに集中し、それによってすべてのアイドル時間を消費しませんか

すべて同じループを実行する1000のスレッドを作成するとどうなりますか?パフォーマンス/ CPUサイクルにどのように影響しますか?

さらに、これはeventsが内部でどのように機能するか? Java、.NET、Javascriptなどのイベント(ボタンを押す、ウィンドウのサイズ変更など)を「聞いている」とき、ループするスレッドが作成されていますか?

8
Rowan Freeman

一般に、CPUが「trueでない間」ループなどを実行するスレッドを作成することは集中的ですか?

はい。このようなループを使用することは ビジー待機 と呼ばれ、それが理由で呼ばれます。これらのビジーループは、プロセッサーが処理できる頻度と速度で状態をチェックするので、ループに十分長く留まると、プロセッサーの負荷は確実に100%になります。

すべて同じループを行うスレッドを1000個作成するとどうなりますか?それはパフォーマンス/ CPUサイクルにどのように影響しますか?

それは、注意を払っているCPUのためにより多くの仕事を作成するだけです。

さらに、これはイベントが内部でどのように機能するのですか? Java、.NET、Javascriptなどのイベント(ボタンを押す、ウィンドウのサイズ変更など)を「聞いている」とき、ループするスレッドが作成されていますか?

いいえ。ビジーループは ポーリング の形式であり、非常に非効率的なループでもあります。オペレーティングシステムには、イベントが発生したことを検出する他のメカニズム(割り込みや特定の呼び出しなど)があり、CPU時間を消費せずにスレッドがイベントを待機できるメカニズムがあります。これらのメカニズムは、Javaなどの言語のイベントメカニズムを実装するためにも使用されます。

あなたの本能は正しいです。 ビジー待機 このように記述されています

スピンは、特定の状況で、特にSMPシステムで実行するように設計されたオペレーティングシステム内でのスピンロックの実装で、有効な戦略になります。ただし、一般に、スピンはアンチパターンと見なされ、回避する必要があります。別のタスクを実行するために使用できるプロセッサ時間は、代わりに無駄なアクティビティに浪費されるためです。

代わりに、たとえば セマフォ または 条件変数 のように、スレッドが実際にアイドル状態になることを可能にする同時実行制御プリミティブを検討する必要があります。

多くのアプリケーションでは、相互排除では不十分です。操作を試行するスレッドは、いくつかの条件が成立するまで待機する必要がある場合があります。次のような忙しい待機ループ

while not( condition ) do 
   // nothing
end

相互排除により、他のスレッドがモニターに入って条件が真になるのを防ぐため、機能しません。他の「解決策」が存在します。モニターのロックを解除し、一定の時間待機し、モニターをロックし、条件Pを確認するループがあるなど。理論的には、機能してデッドロックは発生しませんが、問題が発生します。待機時間の適切な量を決定するのは困難であり、小さすぎるとスレッドがCPUを占有し、大きすぎて明らかに応答しなくなります。必要なのは、条件Pが真である(または真である可能性がある)ときにスレッドに信号を送る方法です。解決策は条件変数です。概念的には、条件変数は、モニターに関連付けられたスレッドのキューであり、スレッドは、ある条件がtrueになるのを待機します。したがって、各条件変数はアサーションに関連付けられています。スレッドが条件変数を待機している間、そのスレッドはモニターを占有しているとは見なされないため、他のスレッドがモニターに入ってモニターの状態を変更する場合があります。ほとんどのタイプのモニターでは、これらの他のスレッドが条件変数に信号を送り、現在の状態でアサーションがtrueであることを示します。

9

スレッドは、変数の変更ではなく、着信イベントを待機する必要があります。

受信イベントは、セマフォが使用可能になる、メッセージキューが空にならない、または時間が経過することです。

semGet()
msqRead()
sleep()

スレッドの観点からは、これらの関数呼び出しはブロックされています。スレッドはイベントが発生するまで待機し、CPUの負荷を他のスレッドに任せます。

システムの観点からは、スレッドは「イベント待ち」としてマークされ、イベントが発生しない限りスケジュールされません。

ハードウェアイベントについては、CPUへの電気信号であり、ISR(割り込みサービスルーチン)の実行をトリガーする割り込みを通じて処理されます。ISR(割り込みサービスルーチン)の役割は、セマフォ、メッセージキュー、または時間でソフトウェアイベントを生成することです。

2
mouviciel

//do nothing一部のセマフォでWAITが通常のシナリオの状態である間にwhile部分が内部にある、または言い換えるとSLEEP。いくつかの割り込みで目が覚めるまでスリープします。したがって、スレッドは「スリープ状態」になるか、「実行していない状態」とだけ言います。実行状態にあるプロセスのみがCPUを消費します。スリープ状態のプロセスはCPUを消費しません。それらはメモリを消費している可能性がありますが、そのメモリは仮想メモリシステムによって内部的にスワップアウトされます。したがって、そのようなスレッドを1000個作成しても、システムに大きな脅威を与えることはありません。

0
Manoj R