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


8

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

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

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

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

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

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

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

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

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


1
プロファイラーはあなたに何を伝えますか?
Arseni Mourzenko 2013年

2
私の質問は一般的です。数字の問題ではなく、「私の理解の何が悪いのか?」
ローワンフリーマン

とった。その後+1。
Arseni Mourzenko 2013年

回答:


12

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

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

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

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

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

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


ありがとう!ループ中にスレッドを短時間(おそらく100ミリ秒)スリープさせるとどうなりますか?スレッドを十分に遅くして、CPUサイクルがそれほど無駄にならず、パフォーマンスが回復するようにしますか?
ローワンフリーマン

1
@RowanFreeman:プロセッサの負荷は軽減されますが、Xが発生したことをOSが通知するのを単に待つよりも、負荷は高くなります。
Bart van Ingen Schenau 2013年

9

あなたの本能は正しいです。 そのように忙しく待っていると説明されています

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

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

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

while not( condition ) do 
   // nothing
end

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


それで、パフォーマンスのヒットの多くを待っている忙しいですか?単一のループ(常に発火していますが)は問題ありませんか
Rowan Freeman

1
@RowanFreemanです。テキストが示唆するように、忙しい待機は、役に立たない命令でCPUサイクルを燃やし続けます(つまりif (!useHasDoneSomething)可能な限り高速に何度も繰り返す)。プログラムでそれを気にしなくても、他のプログラムが実行に使用できる時間を浪費します。しかし、プログラムの内部であっても、忙しいウェイターはいくつかのワーカースレッドに割り当てることができる時間を浪費します(すべてのスレッドを同時に実行するために十分なコアがない場合)。
afsantos 2013年

2
@afsantosビジー待機には有効な使用法があります。通常、代替手段はスレッドのスケジュールを解除し、後で再スケジュールすることを意味します。数CPUサイクル以上ループしないことがわかっている場合は、ビジー待機の方がコンテキストスイッチよりもはるかに効率的です。
アッシリア2013年

1
@assylias確かに、待機時間が非常に短いことがわかっている場合、コンテキストの切り替えは、パフォーマンスへの影響が大きい可能性があります。しかし、私の経験からすると、多忙な待機はしばしば不適切です。OPは彼の個々のケースを評価して、それが価値があるかどうかを確認する必要があります。
afsantos 2013年

2

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

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

semGet()
msqRead()
sleep()

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

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

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


0

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

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