「CPUバウンド」および「I / Oバウンド」という用語はどういう意味ですか?


回答:


452

それはかなり直感的です:

CPUが高速である場合、プログラムが高速になると、プログラムはCPUにバインドされます。πの新しい数字を計算するプログラムは、通常、CPUに依存し、数値を処理するだけです。

I / Oサブシステムが高速である場合、プログラムは高速になるとI / Oバウンドになります。正確なI / Oシステムの意味はさまざまです。私は通常それをディスクに関連付けますが、もちろんネットワークや通信一般も一般的です。ボトルネックとなるのはディスクからのデータの読み取りであるため、巨大なファイルを調べて一部のデータを探すプログラムは、I / Oバウンドになる可能性があります(実際、この例は、最近数百MB /秒の昔ながらの方法のようです) SSDから入ってくる)。


これは、モバイルデバイスでのHTTP通信の理解にどのように結びついていますか?私は、java.nio操作の使用からCPU使用率が急上昇するのを見てきました。
IgorGanapolsky

I / Oは「入力/出力」です。
同志チェ

247

CPUバウンドは、プロセスの進行速度がCPUの速度によって制限されることを意味します。小さな行列の乗算など、小さな数のセットに対して計算を実行するタスクは、CPUにバインドされる可能性があります。

I / Oバウンドとは、プロセスの進行速度がI / Oサブシステムの速度によって制限されることを意味します。たとえば、ファイルの行数をカウントするなど、ディスクからのデータを処理するタスクは、I / Oバウンドである可能性があります。

メモリバウンドとは、プロセスの進行速度が、使用可能なメモリの量とそのメモリアクセスの速度によって制限されることを意味します。大量の行列を乗算するなど、大量のメモリ内データを処理するタスクは、メモリバインドになる可能性があります。

キャッシュバウンドとは、プロセスの進行速度が、使用可能なキャッシュの量と速度によって制限されることを意味します。キャッシュに収まるよりも多くのデータを単純に処理するタスクは、キャッシュバインドされます。

I / Oバウンドは、メモリバウンドがキャッシュバウンドよりも遅く、CPUバウンドよりも遅くなります。

I / Oバウンドになるための解決策は、必ずしもより多くのメモリを取得することではありません。状況によっては、アクセスアルゴリズムは、I / O、メモリ、またはキャッシュの制限に基づいて設計できます。Cache Oblivious Algorithmsを参照してください。


73

マルチスレッド

この回答では、CPUとIOの制限付き作業を区別する1つの重要なユースケース、つまりマルチスレッドコードを記述する場合について調べます。

RAM I / Oバウンドの例:ベクトル合計

単一のベクトルのすべての値を合計するプログラムを考えます。

#define SIZE 1000000000
unsigned int is[SIZE];
unsigned int sum = 0;
size_t i = 0;
for (i = 0; i < SIZE; i++)
    /* Each one of those requires a RAM access! */
    sum += is[i]

コアごとにアレイを均等に分割して並列化することは、一般的な最近のデスクトップでは制限された有用性があります。

たとえば、Ubuntu 19.04では、CPUを搭載したLenovo ThinkPad P51ラップトップ:Intel Core i7-7820HQ CPU(4コア/ 8スレッド)、RAM:2x Samsung M471A2K43BB1-CRC(2x 16GiB)次のような結果が得られます。

ここに画像の説明を入力してください

データをプロットします

ただし、実行の間には多くの差異があることに注意してください。しかし、私はすでに8GiBにいるため、配列サイズをこれ以上増やすことはできません。また、今日の複数の実行にわたる統計の気分ではありません。しかし、これは多くの手動実行を行った後の典型的な実行のように見えました。

ベンチマークコード:

曲線の形を完全に説明するのに十分なコンピューターアーキテクチャがわかりませんが、1つだけ明確です。8つのスレッドをすべて使用しているため、計算が単純に期待される8倍速くなりません。何らかの理由で、2スレッドと3スレッドが最適でしたが、スレッドを追加すると処理が非常に遅くなります。

これを実際に8倍速くなるCPUバウンド作業と比較してください。time(1)の出力で「real」、「user」、「sys」は何を意味しますか?

これは、すべてのプロセッサがRAMにリンクする単一のメモリバスを共有している理由です。

CPU 1   --\    Bus    +-----+
CPU 2   ---\__________| RAM |
...     ---/          +-----+
CPU N   --/

そのため、CPUではなくメモリバスがすぐにボトルネックになります。

これは、2016年のハードウェアでは2つの数値を加算すると1つのCPUサイクルがかかり、メモリの読み取りには約100 CPUサイクルかかるためです。

したがって、入力データのバイトごとに実行されるCPU作業は小さすぎるため、これをIOバウンドプロセスと呼びます。

その計算をさらに高速化する唯一の方法は、マルチチャネルメモリなどの新しいメモリハードウェアで個々のメモリアクセスを高速化することです。

たとえば、より高速なCPUクロックにアップグレードしても、あまり役に立ちません。

その他の例

  • 行列の乗算は、RAMとGPUのCPUに依存します。入力には以下が含まれます。

    2 * N**2
    

    数字ですが:

    N ** 3
    

    乗算が行われます。これは、並列化が実用的な大きなNの価値があるには十分です

    これが、次のような並列CPU行列乗算ライブラリが存在する理由です。

    キャッシュの使用は、実装の速度に大きな違いをもたらします。たとえば、この教訓的なGPU比較の例を参照してください。

    以下も参照してください。

  • ネットワーキングは、典型的なIOバインドの例です。

    1バイトのデータを送信する場合でも、送信先に到達するまでに長い時間がかかります。

    HTTPリクエストのような小さなネットワークリクエストを並列化すると、パフォーマンスが大幅に向上します。

    ネットワークがすでにフルキャパシティにある場合(例:トレントのダウンロード)、並列化によりレイテンシが改善されます(例:「同時に」Webページをロードできる)。

  • 1つの数値を受け取り、それを大量に処理するダミーのC ++ CPUバインド操作:

  • 次の実験に基づくと、ソートはCPUのようです。C++ 17並列アルゴリズムはすでに実装されていますか?並列ソートのパフォーマンスが4倍向上しましたが、より理論的な確認も必要です

CPUバインドかIOバインドかを確認する方法

非RAM IOは、ディスク、ネットワークのようにバインド:ps aux、その後、theck場合CPU% / 100 < n threads。はいの場合、IOバウンドです。たとえば、ブロッキングreadsはデータを待っているだけで、スケジューラはそのプロセスをスキップしています。次に、などのツールを使用してsudo iotop、どのIOが問題であるかを正確に判断します。

実行は迅速で、あなたがスレッドの数をパラメータ場合は、あなたがから簡単にそれを見ることができtime、パフォーマンスCPUバウンドの作業のためのスレッド数の増加に応じて向上:「本当の」、「ユーザー」と「SYS」平均で何time(1)の出力?

RAM-IOバウンド:RAM待機時間はCPU%測定に含まれるため、わかりにくいです。以下も参照してください。

いくつかのオプション:

  • Intel Advisor Roofline(non-free):https : //software.intel.com/en-us/articles/intel-advisor-roofline (archive) "Rooflineチャートは、ハードウェアの制限に関連するアプリケーションのパフォーマンスを視覚的に表したものです。メモリ帯域幅と計算ピークを含む。」

GPU

通常のCPU読み取り可能RAMからGPUに入力データを最初に転送するとき、GPUにはIOボトルネックがあります。

したがって、GPUはCPUにバインドされたアプリケーションのCPUよりも優れているだけです。

ただし、データがGPUに転送されると、GPUは次の理由により、CPUよりも高速にこれらのバイトを操作できます。

  • ほとんどのCPUシステムよりもデータのローカリゼーションが多いため、一部のコアでは他のコアよりも高速にデータにアクセスできます

  • すぐに操作する準備ができていないデータをスキップするだけで、データの並列処理を利用し、レイテンシを犠牲にします。

    GPUは大規模な並列入力データを操作する必要があるため、現在のデータが利用可能になるのを待つのではなく、CPUが主に行うような他のすべての操作をブロックするのではなく、利用可能な次のデータにスキップすることをお勧めします

したがって、アプリケーションが次の場合、GPUはCPUよりも高速になります。

  • 高度に並列化できる:異なるデータのチャンクを同時に別々に処理できる
  • 入力バイトごとに十分な数の操作が必要です(たとえば、バイトごとに1つの加算のみを行うベクトル加算とは異なります)。
  • 入力バイト数が多い

これらのデザインの選択は、もともと3Dレンダリングのアプリケーションを対象としていました。その主な手順は、「OpenGLのシェーダーとは何ですか?

  • 頂点シェーダー:1x4ベクトルの束に4x4行列を掛ける
  • フラグメントシェーダー:三角形との相対的な位置に基づいて、三角形の各ピクセルの色を計算します

したがって、これらのアプリケーションはCPUに依存していると結論付けます。

プログラム可能なGPGPUの出現により、CPUバウンド操作の例として機能するいくつかのGPGPUアプリケーションを観察できます。

以下も参照してください。

CPythonグローバルインタープリターロック(GIL)

簡単なケーススタディとして、Pythonグローバルインタープリターロック(GIL)を指摘したいと思います。CPythonのグローバルインタープリターロック(GIL)とは何ですか?

このCPython実装の詳細により、複数のPythonスレッドがCPUにバインドされた作業を効率的に使用できなくなります。CPythonのドキュメント言います:

CPython実装の詳細:CPythonでは、グローバルインタープリターロックにより、一度に1つのスレッドのみがPythonコードを実行できます(特定のパフォーマンス指向のライブラリーがこの制限を克服する場合があります)。アプリケーションでマルチコアマシンの計算リソースをより有効に利用したい場合は、multiprocessingまたはを使用することをお勧めしますconcurrent.futures.ProcessPoolExecutor。ただし、複数のI / Oバウンドタスクを同時に実行する場合は、スレッド化が適切なモデルです。

したがって、ここでは、CPUバウンドコンテンツが適切でなく、I / Oバウンドが適している例を示します。


1
男、どうやってあなたはどうやってそんなに有能で、このような書き込みをするのですか?
Mikayil Abdullayev

1
@MikayilAbdullayevありがとう!私は「重要な質問」だけに答える傾向があり、私は新しい関連するものを学ぶときに何度も何度もそれらに戻ってくる傾向があります。
Ciro Santilli郝海东冠状病六四事件法轮功

31

CPUバウンドとは、プログラムがCPUまたは中央処理装置によってボトルネックになることを意味し、I / Oバウンドとは、プログラムがI / O、またはディスクやネットワークなどへの読み取りまたは書き込みなどの入出力によってボトルネックになることを意味します。

一般に、コンピュータプログラムを最適化するときは、ボトルネックを見つけて解消しようとします。プログラムがCPUバウンドであることを知ることは、他の何かを不必要に最適化しないようにするのに役立ちます。

[「ボトルネック」とは、プログラムを他の方法よりも遅くすることを意味します。]


22

同じ考えを表現する別の方法:

  • CPUを高速化してもプログラムが高速化しない場合は、I / Oが制限されている可能性があります。

  • I / Oの高速化(たとえば、より高速なディスクの使用)が役に立たない場合は、プログラムがCPUにバインドされている可能性があります。

(他のリソースを考慮する必要があるため、「多分」を使用しました。メモリがその一例です。)


11

プログラムがI / O(ディスクの読み取り/書き込みまたはネットワークの読み取り/書き込みなど)を待機している場合、プログラムが停止していても、CPUは他のタスクを自由に実行できます。プログラムの速度は、主にそのIOが発生する速度に依存します。高速化したい場合は、I / Oを高速化する必要があります。

プログラムが多くのプログラム命令を実行していて、I / Oを待機していない場合、CPUバウンドと呼ばれます。CPUを高速化すると、プログラムの実行が速くなります。

どちらの場合も、プログラムを高速化する鍵はハードウェアを高速化することではなく、プログラムを最適化して必要なIOまたはCPUの量を減らすか、CPUを集中的に使用しながらI / Oを実行させることです。もの。


6

I / Oバウンドとは、計算の完了にかかる時間が主に入出力操作が完了するのを待つために費やされた期間によって決定される状態を指します。

これは、CPUバウンドであるタスクの反対です。この状況は、データが要求される速度がデータが消費される速度よりも遅い場合、つまり、データを処理するよりも多くの時間がデータの要求に費やされる場合に発生します。


6

IOバウンドプロセス:計算よりもIOに多くの時間を費やし、多くの短いCPUバーストがあります。CPUバウンドプロセス:計算に多くの時間を費やし、非常に長いCPUバーストはほとんどありません


2

マイクロソフトの発言をご覧ください。

非同期プログラミングの中核は、非同期操作をモデル化するTaskオブジェクトとTaskオブジェクトです。これらは、asyncおよびawaitキーワードでサポートされています。ほとんどの場合、モデルはかなり単純です。

  • I / Oバウンドコードの場合、非同期メソッド内でタスクまたはタスクを返す操作を待ちます。

  • CPUバインドコードの場合、Task.Runメソッドを使用してバックグラウンドスレッドで開始される操作を待ちます。

awaitキーワードは、魔法が発生する場所です。待機を実行したメソッドの呼び出し元に制御を渡し、最終的にUIの応答性やサービスの弾力性を可能にします。

I / Oバインドの例:Webサービスからのデータのダウンロード

private readonly HttpClient _httpClient = new HttpClient();

downloadButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI as the request
    // from the web service is happening.
    //
    // The UI thread is now free to perform other work.
    var stringData = await _httpClient.GetStringAsync(URL);
    DoSomethingWithData(stringData);
};

CPUバウンドの例:ゲームの計算の実行

private DamageResult CalculateDamageDone()
{
    // Code omitted:
    //
    // Does an expensive calculation and returns
    // the result of that calculation.
}

calculateButton.Clicked += async (o, e) =>
{
    // This line will yield control to the UI while CalculateDamageDone()
    // performs its work.  The UI thread is free to perform other work.
    var damageResult = await Task.Run(() => CalculateDamageDone());
    DisplayDamage(damageResult);
};

上記の例では、非同期を使用して、I / OバウンドおよびCPUバウンドの作業を待機する方法を示しました。コードのパフォーマンスに大きな影響を与え、特定の構成要素の誤用につながる可能性があるため、実行する必要があるジョブがI / OバウンドまたはCPUバウンドである場合を識別することができるのは重要です。

コードを記述する前に、次の2つの質問をする必要があります。

コードは、データベースからのデータなどの何かを「待機」しますか?

  • 答えが「はい」の場合、作業はI / Oバウンドです。

あなたのコードは非常に高価な計算を実行しますか?

  • 「はい」と答えた場合、あなたの仕事はCPUに依存しています。

現在の作業がI / Oバウンドである場合は、非同期を使用し、Task.Run なしで 待機します。Task Parallel Libraryは使用しないでください。この理由は、Async in Depthの記事説明されています。

使用している作業がCPUバウンドであり、応答性を重視する場合は、asyncを使用して待機しますが、Task.Runを使用して別のスレッドで作業を開始します。作業が並行性と並列処理に適している場合は、Task Parallel Libraryの使用も検討する必要があります。


2

実行中の算術/論理/浮動小数点(A / L / FP)のパフォーマンスがプロセッサの理論上のピークパフォーマンス(製造元が提供し、プロセッサ:コアの数、周波数、レジスタ、ALU、FPUなど)。

不可能とは言わないまでも、実際のアプリケーションでピークパフォーマンスを達成することは非常に困難です。ほとんどのアプリケーションは実行のさまざまな部分でメモリにアクセスし、プロセッサは数サイクルの間A / L / FP操作を実行していません。これはフォンノイマン制限と呼ばれています、メモリとプロセッサの間に存在する距離のため、ます。

CPUのピークパフォーマンスに近づけたい場合は、メインメモリからのデータを必要としないようにするために、キャッシュメモリ内のほとんどのデータを再利用する方法が考えられます。この機能を利用するアルゴリズムは、行列と行列の乗算です(両方の行列をキャッシュメモリに格納できる場合)。これは、行列がサイズの場合、FP数のデータのみを使用n x nして2 n^3演算を実行する必要があるために発生し2 n^2ます。一方、たとえば行列の加算n^2は、同じデータを持つFLOP のみを必要とするため、行列の乗算よりもCPUに依存しない、またはメモリに依存するアプリケーションです。

次の図では、Intel i5-9300Hでの行列の加算と行列の乗算の単純なアルゴリズムで取得したFLOPを示しています。

マトリックス加算とマトリックス乗算のFLOP比較

予想通り、行列の乗算のパフォーマンスは行列の加算よりも大きいことに注意してください。これらの結果は、実行することで再現できるtest/gemmtest/matadd、この中で利用できるリポジトリ

この効果についてJ. Dongarraが提供したビデオもご覧になることをお勧めします。


1

I / Oバウンドプロセス:-プロセスの存続期間の大部分がI / O状態で費やされている場合、そのプロセスはAI / Oバウンドプロセスです。例:-計算機、インターネットエクスプローラー

CPUバウンドプロセス:-プロセスライフの大部分がCPUで費やされている場合、CPUバウンドプロセスです。


8
電卓はどのようにIOバウンドプロセスになりますか?確かにそれはCPUバウンドでしょう。あなたの計算機がネットワークまたはディスクにアクセスすることによってブロックされる時間のほとんどを費やしているなら、私はそれで何かがおかしいと思います。
rickerbh 2012年

6
電卓の例ははっきりしていると思いました。ほとんどの場合、ユーザーがボタンを押すのを待機しているため、I / Oを待機しています。
psp 2015

1
@pspは正しいですが、電卓の例は、その名前「電卓」のため、まだioバインドされているとは一見わかりにくいです。これは、プログラムの主な目的が長いCPU計算を実行することであることを意味しますが、デスクトップで計算機を見ると、完了するまでに数ナノ秒かかる計算しか行わない非常に単純な計算機です。したがって、ほとんどの場合、IOであるユーザー入力を待機しています。
Calicoder
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.