web-dev-qa-db-ja.com

マルチスレッド:コアよりも多くのスレッドのポイントは何ですか?

マルチコアコンピューターのポイントは、複数のスレッドを同時に実行できることだと思いました。その場合、クアッドコアマシンを使用している場合、一度に4つ以上のスレッドを実行する意味は何ですか?彼らは互いに時間を盗んでいるだけではないでしょうか?

119
Nick Heiner

答えはスレッドの目的、つまり並列性です。つまり、複数の別々の実行行を一度に実行します。 「理想的な」システムでは、コアごとに1つのスレッドが実行されます。中断はありません。現実にはそうではありません。 4つのコアと4つの作業スレッドがある場合でも、プロセスとそのスレッドは常に他のプロセスとスレッドに切り替えられます。最新のOSを実行している場合、すべてのプロセスには少なくとも1つのスレッドがあり、多くのプロセスにはそれ以上があります。これらのプロセスはすべて一度に実行されています。おそらく現在、マシン上で実行されているスレッドは数百個あります。スレッドが「盗まれる」ことなくスレッドが実行されるような状況になることはありません。 (まあ、それが リアルタイム実行 の場合、リアルタイムOSを使用している場合、またはWindowsでさえリアルタイムスレッドの優先度を使用している場合があります。しかし、それはまれです。)

それを背景として、答え:はい、真の4コアマシン上の4つ以上のスレッドは、「お互いから時間を奪う」状況を与える可能性がありますスレッドには100%のCPUが必要です。スレッドが100%動作していない場合(UIスレッドが動作していないか、スレッドが少量の作業を行っているか、他のスレッドで待機している場合)、実際にスケジュールされている別のスレッドは良い状況です。

実際にはそれよりも複雑です:

  • すべてを一度に行う必要がある5ビットの作業がある場合はどうなりますか? 4つを実行してから5番目を実行するよりも、一度に実行する方が理にかなっています。

  • スレッドが100%CPUを本当に必要とすることはまれです。たとえば、ディスクまたはネットワークI/Oを使用する瞬間は、何も役に立たないのを待つことに時間を費やす可能性があります。これは非常に一般的な状況です。

  • 実行する必要がある作業がある場合、一般的なメカニズムの1つはスレッドプールを使用することです。コアと同じ数のスレッドを持つことは理にかなっているように思えるかもしれませんが、 。Netスレッドプールにはプロセッサごとに最大250のスレッドが利用可能です 。なぜこれを行うのか定かではありませんが、私の推測では、スレッド上で実行するために与えられたタスクのサイズに関係しているのでしょう。

だから:盗むことは悪いことではありません(そして実際には盗難でもありません:それはシステムがどのように動作するかです)。 -バウンド。プロファイリングと測定に基づいて、必要なスレッドの数を把握します。スレッドよりもタスクやジョブの観点で考えると、作業のオブジェクトを作成して実行するプールに渡す方が便利な場合があります。最後に、プログラムが本当にパフォーマンスに重要でない限り、あまり心配しないでください:)

65
David

スレッドが存在するからといって、常にアクティブに実行されているとは限りません。スレッドの多くのアプリケーションには、スレッドが何かを実行するまでスリープ状態になるスレッドの一部が含まれます。たとえば、スレッドを起動するユーザー入力が起動し、処理を行い、スリープ状態に戻ります。

基本的に、スレッドは、他のタスクの進行状況を意識する必要なしに、互いに独立して動作できる個々のタスクです。これらを同時に実行する能力よりも多くの可能性があります。彼らは時々並んで待つ必要がある場合でも、利便性のために依然として有用です。

50
Amber

ポイントは、スレッドカウントがコアカウントを超えたときに実際の速度向上が得られないにもかかわらず、スレッドを使用して、相互依存する必要のないロジックの断片を解くことができるということです。

適度に複雑なアプリケーションであっても、単一のスレッドを使用してすべてをすばやく実行しようとすると、コードの「フロー」のハッシュが作成されます。単一のスレッドはほとんどの時間をこれにポーリングし、それをチェックし、必要に応じて条件付きでルーチンを呼び出します。これにより、細部の汚点以外は見にくくなります。

これを、スレッドをタスク専用にすることができる場合とは対照的に、個々のスレッドを見ると、そのスレッドが何をしているかを見ることができます。たとえば、1つのスレッドがソケットからの入力を待機することをブロックし、ストリームをメッセージに解析し、メッセージをフィルター処理し、有効なメッセージが来たら、他のワーカースレッドに渡します。ワーカースレッドは、他の多くのソースからの入力を処理できます。これらのそれぞれのコードは、他に何もする必要がないことを明示的にチェックする必要なく、クリーンで意図的なフローを示します。

このように作業を分割すると、アプリケーションはオペレーティングシステムに依存してCPUの次の処理をスケジュールできるため、アプリケーション内のどこで何がブロックされ、何が処理できるかについて明示的な条件付きチェックを行う必要がありません。

25
JustJeff

スレッドがリソースを待機している場合(値を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ステートメントの本体がすでにレジスタにロードされている値を使用する場合、プロセッサは条件が評価される前に1つまたは両方のブランチを実行します。条件が戻ると、プロセッサは対応するブランチの結果を適用し、もう一方を破棄します。ここで役に立たない可能性のある作業を実行することは、おそらく別のスレッドに切り替えるよりも優れており、スラッシングにつながる可能性があります。

高クロック速度のシングルコアプロセッサからマルチコアプロセッサに移行したため、チップ設計では、ダイごとのコアの詰め込み、コア間のオンチップリソース共有の改善、分岐予測アルゴリズムの改善、スレッドスイッチングのオーバーヘッドの改善、より良いスレッドスケジューリング。

10
IceArdor

ハードウェアに応じてスレッドを使用して計算を高速化できますが、その主な用途の1つは、使いやすさの理由で一度に複数のことを行うことです。

たとえば、バックグラウンドで処理を行う必要があり、UI入力への応答性を維持する必要がある場合は、スレッドを使用できます。スレッドがないと、重い処理を実行しようとするたびにユーザーインターフェイスがハングします。

この関連する質問も参照してください: スレッドの実用例

6
Cam

理想的な数はCPUごとに1スレッドであるという@kyoryuの主張には強く反対します。

このように考えてください:なぜマルチプロセッシングオペレーティングシステムがあるのですか?ほとんどのコンピューター履歴では、ほぼすべてのコンピューターに1つのCPUが搭載されていました。しかし、1960年代以降、すべての「実際の」コンピューターにはマルチプロセッシング(別名マルチタスク)オペレーティングシステムがありました。

複数のプログラムを実行して、1つは実行でき、他のプログラムはIOなどの理由でブロックされます。

nT以前のWindowsバージョンがマルチタスクであったかどうかについての議論を脇に置いてみましょう。それ以来、すべての実際のOSにはマルチタスクがありました。ユーザーに公開しない人もいますが、とにかく、携帯電話のラジオを聴く、GPSチップと話す、マウス入力を受け付けるなどの操作を行います。

スレッドは、もう少し効率的なタスクです。タスク、プロセス、およびスレッド間に基本的な違いはありません。

CPUは無駄になる恐ろしいものなので、できる限り多くのCPUを使用する準備をしてください。

C、C++、Javaなど、ほとんどの手続き型言語では、適切なスレッドセーフコードを記述するのは大変な作業です。今日の市場には6コアCPUがあり、16コアCPUはありませんマルチスレッドはますます重要な要件であるため、遠く離れた人々はこれらの古い言語から離れることが予想されます。

@kyoryuとの意見の相違は単なる私見であり、残りは事実です。

6
fishtoprecords

任意の数の要求を処理する必要があるWebサーバーを想像してください。それ以外の場合、新しいリクエストはすべて、他のすべてのリクエストが完了するまで待機する必要があるため(インターネット経由での応答の送信を含む)、リクエストを並行して処理する必要があります。この場合、ほとんどのWebサーバーのコア数は、通常処理するリクエストの数よりも少なくなります。

また、サーバーの開発者にとっても簡単になります。リクエストを処理するスレッドプログラムを書くだけでよく、複数のリクエストを保存すること、リクエストを処理する順序などについて考える必要はありません。

5
tobiw

上記の回答のほとんどは、パフォーマンスと同時操作について説明しています。別の角度からこれにアプローチします。

たとえば、単純なターミナルエミュレーションプログラムの場合を考えてみましょう。次のことを行う必要があります。

  • リモートシステムからの着信キャラクターを監視し、表示します
  • キーボードから来るものを監視し、リモートシステムに送信する

(実際の端末エミュレーターは、入力した内容をディスプレイにエコー表示するなど、さらに多くの機能を備えていますが、ここではそれを引き継ぎます。)

これで、次の擬似コードのように、リモートから読み取るためのループが簡単になりました。

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にバインドされたプロセスの応答性を高めることです(全体的に効率が悪くても)。また、ロジックを理解しやすくすることも重要です(ただし、共有状態を最小化する場合のみ)。それは多くのものであり、ケースバイケースでその利点がその欠点を上回るかどうかを判断する必要があります。

多くのスレッドがスリープ状態になり、ユーザー入力、I/O、およびその他のイベントを待機します。

3
Puppy

スレッドは、UIアプリケーションの応答性に役立ちます。さらに、スレッドを使用して、コアからより多くの作業を取得できます。たとえば、シングルコアでは、1つのスレッドがIOを実行し、別のスレッドが何らかの計算を実行できます。シングルスレッドの場合、コアはIOは完了です。これは非常に高いレベルの例ですが、スレッドを使用してCPUをもう少し強く叩くことができます。

2
Anon

プロセッサ、またはCPUは、システムに接続される物理チップです。プロセッサは複数のコアを持つことができます(コアは、命令を実行できるチップの一部です)。コアは、複数のスレッドを同時に実行できる場合、オペレーティングシステムからは複数の仮想プロセッサとして認識されます(スレッドは命令の単一シーケンスです)。

プロセスは、アプリケーションの別名です。一般的に、プロセスは互いに独立しています。 1つのプロセスが停止しても、別のプロセスが停止することはありません。プロセスは、メモリやI/Oなどのリソースを通信したり共有したりすることができます。

各プロセスには、個別のアドレス空間とスタックがあります。プロセスには複数のスレッドを含めることができ、各スレッドは同時に命令を実行できます。プロセス内のすべてのスレッドは同じアドレス空間を共有しますが、各スレッドには独自のスタックがあります。

これらの定義と、これらの基礎を使用したさらなる研究があなたの理解に役立つことを願っています。

2
Srikar Doddi

一部のAPIの設計方法では、no choiceがありますが、それらを別のスレッド(ブロッキング操作を伴うもの)で実行します。例としては、PythonのHTTPライブラリ(AFAIK)があります。

通常、これは大した問題ではありません(問題である場合、OSまたはAPIは、代替の非同期操作モード、つまりselect(2)とともに出荷する必要があります)。 I/Oの完了を待っている間、スリープ状態になります。一方、何かが重い計算をしている場合は、have GUIスレッドとは別のスレッドに配置します(手動多重化を楽しんでいない限り)。

これは非常に古い質問であり、多くの良い答えがありますが、現在の環境で重要なことを指摘するためにここにいます:

マルチスレッド用のアプリケーションを設計する場合、特定のハードウェア設定用に設計するべきではありません。 CPUテクノロジーは長年にわたって急速に進歩しており、コア数は着実に増加しています。 4つのスレッドのみを使用するようにアプリケーションを意図的に設計する場合、オクタコアシステム(たとえば)で自分自身を制限する可能性があります。現在、20コアシステムでさえも市販されているため、このような設計は間違いなく良いことよりも害をもたらします。

1
Jai

スレッドの理想的な使用法は、実際、コアごとに1つです。

ただし、非同期/非ブロッキングIOを排他的に使用しない限り、スレッドがIOでブロックされる可能性が高く、CPUを使用しません。

また、典型的なプログラミング言語では、CPUごとに1つのスレッドを使用するのが多少難しくなります。並行性を中心に設計された言語(Erlangなど)を使用すると、余分なスレッドを簡単に使用できなくなります。

1
kyoryu

最初の推測に応えて:マルチコアマシンは、単一のプロセスの複数のスレッドだけでなく、複数のプロセスを同時に実行できます。

最初の質問に対する答えとして、複数のスレッドのポイントは、通常、1つのアプリケーション内で複数のタスクを同時に実行することです。ネット上の典型的な例は、メールを送受信する電子メールプログラムと、ページ要求を送受信するWebサーバーです。 (Windowsなどのシステムを1つのスレッドのみ、または1つのプロセスのみに実行することは本質的に不可能であることに注意してください。Windowsタスクマネージャーを実行すると、通常、アクティブプロセスの長いリストが表示されます。 )

2番目の質問に対する回答:ほとんどのプロセス/スレッドはCPUバウンドではありません(つまり、連続して中断することなく実行されます)。代わりに、I/Oが終了するまで頻繁に停止して待機します。その待機中、他のプロセス/スレッドは、待機中のコードから「盗む」ことなく実行できます(単一のコアマシン上であっても)。

0
joe snyder