C# でスレッドを学習しています。ただし、スレッドのどの側面が実際にパフォーマンスを向上させているのか理解できません。
シングル コア プロセッサのみが存在するシナリオを考えてみましょう。タスクを複数のスレッドに分割すると、同じプロセス コンテキスト (共有リソース) が使用され、同時に実行されます。スレッドは時間を共有しているだけなので、実行時間 (ターンアラウンド タイム) がシングル スレッド プロセスよりも短いのはなぜでしょうか?
C# でスレッドを学習しています。ただし、スレッドのどの側面が実際にパフォーマンスを向上させているのか理解できません。
シングル コア プロセッサのみが存在するシナリオを考えてみましょう。タスクを複数のスレッドに分割すると、同じプロセス コンテキスト (共有リソース) が使用され、同時に実行されます。スレッドは時間を共有しているだけなので、実行時間 (ターンアラウンド タイム) がシングル スレッド プロセスよりも短いのはなぜでしょうか?
シングル コア CPU で得られる利点は、非同期性によるものです。スレッドを使用することは、それを実現する 1 つの方法です (ただし、唯一の方法ではありません)。
食事を作るプロセスを想像してみてください。どちらが速いと思いますか:
または代わりに:
私の経験から、2番目の方が速いです。
ここでの一般的な考え方は、プログラミングの多くの状況では、ある程度時間がかかる操作が発生しますが、CPU からの作業を完了する必要はないということです。一般的な例は IO です。情報を取得するためにデータベースにリクエストを送信すると、そのリクエストが戻ってくるのを待っている間に他のことをしなければならないことがよくあります。おそらく、いくつかの要求を送信してから、1 つの要求を開始して待機し、次の要求を開始して待機するという方法ではなく、それらが終了するのを待つことができます (ただし、後者を行う必要がある場合もあります)。
ここで、実行する必要がある作業が CPU バウンドの作業である場合、CPU に複数のコアがあり、作業が実際に非同期ではなく並列で実行できる場合にのみ、スレッド化からメリットが得られます。たとえば、多くのグラフィックス関連の作業 (簡単な例を挙げると行列の乗算) には、多くの基本的な計算が必要になることがよくあります。複数のコアがある場合、これらの操作は多くの場合、非常にうまくスケーリングされます。複数のコア (または、事実上、非常に小さくて単純なコアを多数備えた CPU である GPU ) がない場合、スレッドを使用する意味はあまりありません。
あなたが持っているコメントのほとんどは正しいですが、私も2セントを捨てます(そしてここにコメントをリストします):
Jonesy: 「スレッド化はマルチコア環境で最も効率的です」 -> はい、しかしこれはシングルコア CPU です...だから私はこれに戻ります.
KooKiz と John Sively: どちらも I/O について言及しています。あなたのマシンは 100% 常にフルパワーで動いているわけではありません。他にも時間がかかる非常に多くのことが起こっており、それらのイベントの間、CPU は休憩を取ります。
(参照ポイント: I/O は、ネットワーク転送、ハードディスク/RAM の読み取り、SQL クエリなどです。新しいデータを CPU に取り込み、CPU からデータをオフロードするものはすべて)
これらの休憩は、CPU が他のことを行うことができる時間です。シングル コア CPU (現時点ではハイパースレッディングは無視します) とシングル スレッド アプリケーションを使用している場合、問題なく動作します。ただし、常に実行されるわけではありません。CPU スケジューリングは、1 つか 2 つのサイクルを与えてから別の作業に進み、しばらくしてからプログラムに戻って、さらに数サイクル与えて先に進む、などです。一度に」をシングルコア CPU で実行します。
さて、これは通常のプログラムであり、値をキャッシュに直接書き込む非常に小さなアセンブリ プログラムではないため、プログラムはデータを RAM に格納します... CPU キャッシュに比べて比較的遅い記憶媒体です。このため、値のロードには時間がかかります。
この間、CPU が何もすることがない可能性があります。これは、シングル コアであっても、マルチスレッド アプリケーションの高速化を確認できる場所です。他のスレッドは、CPU がアイドル状態になる余分な CPU サイクルを埋めます。
2:1 のスピードアップが見られる可能性はほとんどないことに注意してください。2 スレッドのプログラムでは、10 ~ 20% の速度向上しか見られない可能性が高くなります。「他の」スレッド (特定の時点で I/O を実行していないスレッド) は、最初のスレッドが I/O を実行している間だけ、実際にはフル キャパシティで実行されることに注意してください。
ただし、多くの場合、実際には最悪の時間が表示されます。これは、CPU がプロセス内のスレッド間の切り替えにより多くの時間を費やさなければならないためです (一度に 1 つのことしか実行できないことを思い出してください!)。これをオーバーヘッドと呼びます。2 番目のスレッドは、それが補える以上のオーバーヘッドを作成するため、プロセス全体が遅くなります。
マルチコア マシンでは、2 つの物理エグゼキューターがあります。つまり、2 番目のスレッドがまったく新しいコアで動作します。これは、実行時間に関して他の多くのものと競合する必要がないことを意味します。したがって、ここで大幅なスピードアップが得られます。
もちろん、クラスター上で実行されるマルチプロセス プログラムもありますが、それについては別の機会に取っておきます。
計算が制御の並行スレッドに分割されると、ターンアラウンド タイムが変わります。
それぞれ 10 分かかる 2 つの計算を実行したいとします。
これらを連続してスケジュールする場合 (マルチスレッドなし)、10 分で 1 つの計算の結果が得られ、別の 10 分で別の計算の結果が得られます。
計算の間にタイム スライスを適用すると、20 分待たなければならず、20 分が経過すると、突然両方の結果が得られます。
2 つの計算を実行したいとします。1 つは 1 分、もう 1 つは 59 分かかりますが、これはわかりません。(覚えておいてください、私たちはコードを理解しない単なるスケジューラーです。)
2 つのジョブを 1 つずつ実行すると、59 分のジョブが最初にスケジュールされる可能性があります。そのため、1 つの結果が出るまで 59 分、2 番目の結果が出るまでさらに 1 分待たなければなりません。基本的に両方の結果を 1 時間待ちます。
運が良ければ、短い方のジョブを最初に実行し、最初の結果を 1 分で取得し、2 番目の結果を 59 分後に取得します。平均ターンアラウンド タイムははるかに短くなっています。
しかし、スレッドを使用してジョブ間をタイム スライスするとします。次に、最初のジョブの結果を 2 分で取得し、2 番目のジョブの結果を 58 分後に取得します。これは 2 番目のシナリオとほぼ同じですが、どの仕事が短い仕事になるかを予測する必要はありません。
純粋に CPU バウンドのタスクのタイム スライスを使用したスレッド化は、非常に大きなジョブが、その大きなジョブを完了するのに必要な時間だけ他のすべてを遅らせるという病的なケースを回避するのに役立ちます。
スレッド化によって本質的にプロセスが高速化されるわけではないことに注意することが重要です。同じプロセスを競合すると、必要なランタイムが減少するどころか増加する場合があります。行うべき適切な評価は、目的のシナリオが最初にマルチスレッド化の恩恵を受けるかどうかです。
スレッド化の基本的な要点は、利用可能なリソースでマルチタスクを行うことです。KooKiz が指摘するように、利用可能な場合は残りの CPU 時間を使用するのと同じです。しかし、その通りです。スレッド化を使用してもランタイムが改善されない場合があります。
ただし、シングル コア システムでも、マルチスレッドによってパフォーマンスが向上する場合があります。1 つのプロセスが何かを待機している場合、タンデムで実行されている他のプロセスがロックアウトされることはありません。待機時間に応じて、単一のコアが他の独立したプロセス間をジャンプして、全体として時間を節約できます。