マルチコアコンピューターのポイントは、複数のスレッドを同時に実行できることだと思いました。その場合、クアッドコアマシンを使用している場合、一度に4つ以上のスレッドを実行する意味は何ですか?彼らは単にお互いから時間(CPUリソース)を盗んでいるのではないでしょうか?
マルチコアコンピューターのポイントは、複数のスレッドを同時に実行できることだと思いました。その場合、クアッドコアマシンを使用している場合、一度に4つ以上のスレッドを実行する意味は何ですか?彼らは単にお互いから時間(CPUリソース)を盗んでいるのではないでしょうか?
回答:
答えは、並列処理であるスレッドの目的を中心に展開します。つまり、一度に複数の個別の実行行を実行します。「理想的な」システムでは、コアごとに1つのスレッドが実行されます。中断はありません。実際にはそうではありません。4つのコアと4つの作業スレッドがある場合でも、プロセスとそのスレッドは常に他のプロセスとスレッドに切り替えられます。最新のOSを実行している場合、すべてのプロセスには少なくとも1つのスレッドがあり、多くのスレッドにはそれ以上のスレッドがあります。これらのプロセスはすべて同時に実行されています。おそらく数百のスレッドがすべてあなたのマシンで今走っているでしょう。時間を奪われることなくスレッドが実行されるという状況は発生しません。(まあ、それがリアルタイムで実行されている場合、、リアルタイムOSを使用している場合、またはWindowsの場合でも、リアルタイムスレッドの優先度を使用します。しかし、それはまれです。)
それを背景として、答え:はい、真の4コアマシンで4つを超えるスレッドを使用すると、「互いの時間を奪う」という状況が発生する可能性があります。 個々のスレッドが100%のCPUを必要とする場合にのみ、それらが。スレッドが100%機能していない場合(UIスレッドが機能していない場合、またはスレッドが少量の作業を行っているか、他の何かを待機している場合)、スケジュールされている別のスレッドが実際には良い状況です。
実際にはそれよりも複雑です。
5つすべての作業を一度に行う必要がある場合はどうでしょうか。それらを4つ実行してから5番目に実行するよりも、一度にすべてを実行する方が理にかなっています。
スレッドが本当に100%のCPUを必要とすることはまれです。たとえば、ディスクまたはネットワークI / Oを使用する瞬間、それは潜在的に何も役に立たずに待機する時間を費やす可能性があります。これは非常に一般的な状況です。
実行する必要がある作業がある場合、1つの一般的なメカニズムはスレッドプールを使用することです。コアと同じ数のスレッドを使用することは理にかなっているように見えるかもしれませんが、.Netスレッドプールには、プロセッサーごとに最大250のスレッドを使用できます。彼らがこれを行う理由はわかりませんが、私の推測では、スレッドで実行するために指定されたタスクのサイズに関係しています。
つまり、時間を盗むことは悪いことではありません(実際の盗難でもありません。システムの動作方法です)。スレッドが実行する処理の種類に基づいてマルチスレッドプログラムを作成します。CPUではない場合があります。 -バウンド。プロファイリングと測定に基づいて、必要なスレッドの数を把握します。スレッドではなく、タスクまたはジョブの観点から考える方が便利な場合があります。作業オブジェクトを記述して、実行するためにそれらをプールに割り当てます。最後に、プログラムが本当にパフォーマンスクリティカルでない限り、あまり心配しないでください:)
スレッドが存在するからといって、必ずしもアクティブに実行されているとは限りません。スレッドの多くのアプリケーションには、スレッドがウェイクアップし、処理を行って、スリープに戻るなど、何かをするときまでスリープするいくつかのスレッドが含まれます。
基本的に、スレッドは、互いに独立して動作できる個別のタスクであり、別のタスクの進行状況を意識する必要はありません。同時に実行する能力よりも多くの可能性があります。それらは時々互いの後ろに並んで待つ必要があるとしても、便利のためにまだ役に立ちます。
重要なのは、スレッド数がコア数を超えたときに実際のスピードアップが得られなくても、スレッドを使用して相互に依存する必要のないロジックの断片を解きほぐすことができるということです。
中程度に複雑なアプリケーションでも、シングルスレッドを使用してすべてをすばやく実行すると、コードの「フロー」のハッシュが作成されます。単一のスレッドはほとんどの時間をこれのポーリングに費やし、それをチェックし、必要に応じて条件付きでルーチンを呼び出し、細かい部分のモラス以外は何も見えなくなります。
これを、スレッドをタスク専用にして、個々のスレッドを見ると、そのスレッドの動作を確認できる場合とは対照的です。たとえば、あるスレッドがソケットからの入力の待機をブロックし、ストリームをメッセージに解析し、メッセージをフィルタリングし、有効なメッセージが来たら、他のいくつかのワーカースレッドに渡します。ワーカースレッドは、他の多くのソースからの入力を処理できます。これらのそれぞれのコードは、他に何かする必要がないことを明示的にチェックする必要なしに、クリーンで意図的なフローを示します。
このように作業を分割することで、アプリケーションはオペレーティングシステムに依存して、CPUで次に何をするかをスケジュールできます。そのため、アプリケーション内のどこにいても、何がブロックされ、処理の準備ができているかについて明示的な条件チェックを行う必要はありません。
スレッドがリソースを待機している場合(RAMからレジスターへの値のロード、ディスクI / O、ネットワークアクセス、新しいプロセスの起動、データベースへのクエリ、ユーザー入力の待機など)、プロセッサは別のスレッド、およびリソースが利用可能になると最初のスレッドに戻ります。これにより、CPUはアイドル状態にする代わりに数百万の操作を実行できるため、CPUがアイドル状態になる時間を短縮できます。
ハードドライブからデータを読み取る必要があるスレッドについて考えてみます。2014年、一般的なプロセッサコアは2.5 GHzで動作し、サイクルごとに4つの命令を実行できる可能性があります。0.4 nsのサイクルタイムで、プロセッサはナノ秒あたり10命令を実行できます。一般的な機械式ハードドライブのシーク時間は約10ミリ秒で、プロセッサはハードドライブから値を読み取るのにかかる時間で1億の命令を実行できます。順次読み取りまたはハイブリッドセクションからの読み取りのデータ待機時間が数桁速くなる可能性があるため、小さなキャッシュ(4 MBバッファー)を備えたハードドライブと数GBのストレージを備えたハイブリッドドライブでは、パフォーマンスが大幅に向上する可能性があります。
プロセッサコアはスレッドを切り替えることができ(スレッドの一時停止と再開のコストは約100クロックサイクルです)、最初のスレッドは高遅延入力(レジスタ(1クロック)とRAM(5ナノ秒)よりも高価なもの)を待機します。ディスクI / O、ネットワークアクセス(待ち時間250ミリ秒)、CDまたは低速バスからのデータの読み取り、またはデータベース呼び出し。コアよりもスレッド数が多いということは、待ち時間の長いタスクを解決しながら、有用な作業を実行できることを意味します。
CPUにはスレッドスケジューラがあり、各スレッドに優先順位を割り当て、スレッドをスリープ状態にして、所定の時間後に再開できるようにします。スレッドスケジューラの仕事はスラッシングを減らすことです。スラッシングは、各スレッドが再びスリープ状態になる前に100命令しか実行しない場合に発生します。スレッドの切り替えのオーバーヘッドにより、プロセッサコアの合計スループットが低下します。
このため、問題を適切な数のスレッドに分割することをお勧めします。行列の乗算を実行するコードを記述している場合、出力行列のセルごとに1つのスレッドを作成するのは過剰ですが、行ごとまたはnごとに1つのスレッドますが、出力行列の行行を使用すると、スレッドの作成、一時停止、および再開のオーバーヘッドコストを削減できます。
これは、分岐予測が重要である理由でもあります。RAMからの値のロードを必要とするifステートメントがあるが、ifおよびelseステートメントの本体がすでにレジスターにロードされている値を使用している場合、プロセッサーは条件が評価される前に一方または両方の分岐を実行する可能性があります。条件が戻ると、プロセッサは対応する分岐の結果を適用し、もう一方を破棄します。ここで役に立たない可能性のある作業を実行することは、スラッシングにつながる可能性がある別のスレッドに切り替えるよりもおそらく優れています。
高速クロックのシングルコアプロセッサからマルチコアプロセッサに移行したため、チップ設計は、ダイごとのコアの詰め込み、コア間のオンチップリソース共有の改善、ブランチ予測アルゴリズムの改善、スレッドスイッチングのオーバーヘッドの改善に重点を置いています。そしてより良いスレッドスケジューリング。
上記の回答のほとんどは、パフォーマンスと同時操作について述べています。私は別の角度からこれに取り組みます。
たとえば、単純な端末エミュレーションプログラムの場合を考えてみましょう。次のことを行う必要があります。
(実際の端末エミュレーターは、入力したものをディスプレイにエコーする可能性も含めて、さらに多くのことを行いますが、ここではそれを渡します。)
これで、リモートから読み取るためのループは、次の擬似コードのように単純になります。
while get-character-from-remote:
print-to-screen character
キーボードを監視して送信するためのループも簡単です。
while get-character-from-keyboard:
send-to-remote character
ただし、問題は、これを同時に行う必要があることです。スレッド化されていない場合、コードは次のようになるはずです。
loop:
check-for-remote-character
if remote-character-is-ready:
print-to-screen character
check-for-keyboard-entry
if keyboard-is-ready:
send-to-remote character
この意図的に簡略化された例でも、実際の通信の複雑さを考慮に入れていないロジックは、非常に難読化されています。ただし、スレッディングを使用すると、単一コアでも、2つの疑似コードループは、ロジックをインターレースすることなく独立して存在できます。どちらのスレッドもほとんどがI / Oバウンドであるため、厳密に言えば、統合ループよりもCPUリソースを浪費しますが、CPUに大きな負荷をかけません。
もちろん、実際の使用法は上記よりもさらに複雑です。しかし、アプリケーションにさらに懸念を加えると、統合ループの複雑さは指数関数的に増加します。ロジックはますます断片化しており、状態マシン、コルーチンなどのようなテクニックを使用して、物事を管理しやすくする必要があります。管理は可能ですが、読み取りはできません。スレッド化により、コードが読みやすくなります。
では、なぜスレッドを使用しないのでしょうか。
まあ、タスクがI / OバウンドではなくCPUバウンドの場合、スレッド化は実際にシステムの速度を低下させます。パフォーマンスが低下します。多くの場合、多くの場合。(「スラッシング」は、CPUにバインドされたスレッドを多く落とすとよくある問題です。スレッド自体のコンテンツを実行するよりも、アクティブなスレッドを変更するのに時間がかかります。)また、上記のロジックの理由の1つはとても単純なので、私は非常に意図的に単純化した(そして非現実的な)例を選択しました。画面に入力された内容をエコーしたい場合は、共有リソースのロックを導入することで、新たな傷の世界が生まれます。共有リソースが1つだけの場合、これはそれほど問題ではありませんが、共有するリソースが増えるにつれて、ますます大きな問題になり始めます。
結局のところ、スレッド化は多くのことについてです。たとえば、すでに述べたように、I / Oバウンドプロセスの応答性を向上させることです(全体的な効率が低くても)。また、ロジックを理解しやすくすることも目的です(ただし、共有状態を最小限に抑える場合のみ)。それは多くのものについてであり、あなたはその利点がケースバイケースでその欠点を上回るかどうか決定しなければなりません。
ハードウェアによっては、計算を高速化するためにスレッドを確実に使用できますが、その主な用途の1つは、ユーザーフレンドリーの理由で一度に複数のことを実行することです。
たとえば、バックグラウンドで処理を行う必要があり、UI入力への応答性も維持する必要がある場合は、スレッドを使用できます。スレッドがないと、重い処理を実行しようとするたびにユーザーインターフェイスがハングします。
この関連する質問も参照してください:スレッドの実用的な使用
理想的な数はCPUごとに1つのスレッドであるという@kyoryuの主張に強く同意しません。
このように考えてください。なぜマルチプロセッシングオペレーティングシステムがあるのですか?ほとんどのコンピューターの履歴では、ほぼすべてのコンピューターに1つのCPUが搭載されていました。それでも1960年代以降、すべての「実際の」コンピューターにはマルチプロセッシング(別名マルチタスク)オペレーティングシステムがありました。
複数のプログラムを実行して、1つのプログラムを実行し、他のプログラムをIOなどでブロックします。
NTより前のWindowsバージョンがマルチタスクであったかどうかについての引数を脇に置いておきましょう。それ以来、すべての実際のOSにマルチタスクがありました。一部のユーザーはそれをユーザーに公開しませんが、とにかく、携帯電話のラジオを聞いたり、GPSチップと話したり、マウス入力を受け入れたりすることなどを行います。
スレッドは、もう少し効率的なタスクにすぎません。タスク、プロセス、スレッドの間に基本的な違いはありません。
CPUは非常に無駄になるので、できるだけ多くの物を用意しておいてください。
ほとんどの手続き型言語(C、C ++、Javaなど)では、適切なスレッドセーフコードを書くことは多くの作業であることに同意します。今日の市場には6コアCPUがあり、16コアCPUもそう遠くないので、マルチスレッド化がますます重要な要件となっているため、人々はこれらの古い言語から遠ざかることを期待しています。
@kyoryuとの不一致は単なる私見であり、残りは事実です。
任意の数のリクエストを処理する必要があるWebサーバーを想像してみてください。それ以外の場合、新しいリクエストはすべて、他のすべてのリクエストが完了するまで(インターネット経由でのレスポンスの送信を含む)待機する必要があるため、リクエストを並行して処理する必要があります。この場合、ほとんどのWebサーバーのコア数は、通常処理する要求の数よりもはるかに少なくなります。
また、サーバーの開発者にとっても簡単になります。要求を処理するスレッドプログラムを作成するだけでよく、複数の要求の格納や処理順序などを考慮する必要がありません。
多くのスレッドはスリープ状態になり、ユーザー入力、I / O、およびその他のイベントを待機します。
スレッドは、UIアプリケーションの応答性に役立ちます。さらに、スレッドを使用して、コアからより多くの作業を取得できます。たとえば、シングルコアでは、1つのスレッドがIOを実行し、別のスレッドがいくつかの計算を実行できます。シングルスレッドの場合、コアは基本的にIOが完了するのを待機してアイドル状態になる可能性があります。これはかなり高いレベルの例ですが、スレッドを使用してCPUを少し難しくすることができます。
プロセッサーまたはCPUは、システムに接続されている物理チップです。プロセッサは複数のコアを持つことができます(コアは、命令を実行できるチップの一部です)。コアは、複数のスレッドを同時に実行できる場合(スレッドは単一の命令シーケンス)、オペレーティングシステムからは複数の仮想プロセッサのように見えます。
プロセスは、アプリケーションの別名です。一般に、プロセスは互いに独立しています。1つのプロセスが停止しても、別のプロセスも停止することはありません。プロセスが通信したり、メモリやI / Oなどのリソースを共有したりすることが可能です。
各プロセスには、個別のアドレス空間とスタックがあります。プロセスには複数のスレッドを含めることができ、それぞれが同時に命令を実行できます。プロセス内のすべてのスレッドは同じアドレス空間を共有しますが、各スレッドには独自のスタックがあります。
うまくいけば、これらの定義とこれらの基礎を使用したさらなる研究があなたの理解に役立つことを願っています。
スレッドの理想的な使用法は、実際、コアごとに1つです。
ただし、非同期/非ブロックIOを排他的に使用しない限り、IOでスレッドがブロックされ、CPUを使用しない可能性が高くなります。
また、一般的なプログラミング言語では、CPUごとに1つのスレッドを使用することがやや難しくなっています。並行性を中心に設計された言語(Erlangなど)は、余分なスレッドを使用しないようにすることができます。
一部のAPIの設計方法では、別のスレッド(ブロッキング操作を伴うもの)で実行するしかありません。例としては、PythonのHTTPライブラリ(AFAIK)があります。
通常、これはそれほど問題にはなりません(問題である場合、OSまたはAPIは代替の非同期動作モードで出荷されます:)。select(2)
これはおそらく、スレッドがI / O完了。一方、何かが重い計算を行っている場合は、GUIスレッドとは別のスレッドに置く必要があります(手動多重化を楽しんでいない場合)。
最初の予想に応えて:マルチコアマシンは、単一のプロセスの複数のスレッドだけでなく、複数のプロセスを同時に実行できます。
最初の質問への回答:複数のスレッドのポイントは通常、1つのアプリケーション内で複数のタスクを同時に実行することです。ネット上の古典的な例は、メールを送受信する電子メールプログラム、およびページ要求を送受信するWebサーバーです。(Windowsのようなシステムを1つのスレッドまたは1つのプロセスのみを実行するように減らすことは基本的に不可能であることに注意してください。Windowsタスクマネージャーを実行すると、通常、アクティブなプロセスの長いリストが表示されます。その多くは複数のスレッドを実行します。 )
2番目の質問への回答:ほとんどのプロセス/スレッドはCPUにバインドされていない(つまり、継続的に実行され、中断されない)ではなく、I / Oが終了するまで頻繁に停止して待機します。その待機中、他のプロセス/スレッドは、待機中のコードから「盗む」ことなく実行できます(単一のコアマシン上でも)。
スレッドとは、一連の操作と同じくらい簡単にコードを記述できる抽象概念であり、幸いにも、コードが他のコードとインターレースされて実行されることや、IOを待機して待機していること、または他のスレッドを待機していることを認識している場合があります。イベントまたはメッセージ。
ポイントは、大多数のプログラマーがステートマシンの設計方法を理解していないことです。独自のスレッドにすべてを入れることができるため、プログラマーは、進行中のさまざまな計算の状態を効率的に表現して、中断して後で再開できるようにする方法を考える必要がなくなります。
例として、非常にCPUを集中的に使用するタスクであるビデオ圧縮を考えます。GUIツールを使用している場合は、おそらくインターフェイスの応答性を維持する必要があります(進行状況の表示、キャンセル要求への応答、ウィンドウのサイズ変更など)。したがって、一度に大きなユニット(1つ以上のフレーム)を処理するようにエンコーダーソフトウェアを設計し、UIとは別の独自のスレッドで実行します。
もちろん、進行中のエンコード状態を保存してプログラムを閉じて再起動したり、リソースを大量に消費するゲームをプレイしたりできるとしたら、状態マシンの設計方法を始まり。それか、またはOSのプロセス休止のまったく新しい問題を設計して、個々のアプリをディスクに一時停止および再開できるようにすることを決定します...