Was bedeuten die Begriffe "CPU-gebunden" und "E / A-gebunden"?

Antworten:

452

Es ist ziemlich intuitiv:

Ein Programm ist CPU-gebunden, wenn es schneller laufen würde, wenn die CPU schneller wäre, dh es verbringt den größten Teil seiner Zeit damit, einfach die CPU zu verwenden (Berechnungen durchzuführen). Ein Programm, das neue Ziffern von π berechnet, ist normalerweise CPU-gebunden, es knackt nur Zahlen.

Ein Programm ist E / A-gebunden, wenn es schneller gehen würde, wenn das E / A-Subsystem schneller wäre. Welches genaue E / A-System gemeint ist, kann variieren. Normalerweise verbinde ich es mit Festplatte, aber natürlich ist auch die Vernetzung oder Kommunikation im Allgemeinen üblich. Ein Programm, das eine große Datei nach einigen Daten durchsucht, kann E / A-gebunden werden, da der Engpass dann das Lesen der Daten von der Festplatte ist (tatsächlich ist dieses Beispiel heutzutage mit Hunderten von MB / s vielleicht etwas altmodisch von SSDs kommen).

entspannen
quelle
Wie hängt dies mit dem Verständnis der HTTP-Kommunikation auf einem mobilen Gerät zusammen? Ich habe einen Anstieg der CPU-Auslastung durch die Verwendung von java.nio- Operationen festgestellt .
IgorGanapolsky
E / A ist "Eingabe / Ausgabe".
Genosse Che
246

CPU-gebunden bedeutet, dass die Geschwindigkeit, mit der der Prozess fortschreitet, durch die Geschwindigkeit der CPU begrenzt wird. Eine Aufgabe, die Berechnungen für einen kleinen Satz von Zahlen durchführt, beispielsweise das Multiplizieren kleiner Matrizen, ist wahrscheinlich CPU-gebunden.

E / A-gebunden bedeutet, dass die Geschwindigkeit, mit der ein Prozess fortschreitet, durch die Geschwindigkeit des E / A-Subsystems begrenzt ist. Eine Aufgabe, die Daten von der Festplatte verarbeitet, z. B. die Anzahl der Zeilen in einer Datei zählt, ist wahrscheinlich an die E / A gebunden.

Speicher gebunden bedeutet, dass die Geschwindigkeit, mit der ein Prozess fortschreitet, durch die verfügbare Speichermenge und die Geschwindigkeit dieses Speicherzugriffs begrenzt ist. Eine Aufgabe, die große Mengen an Speicherdaten verarbeitet, beispielsweise das Multiplizieren großer Matrizen, ist wahrscheinlich speichergebunden.

Cache-gebunden bedeutet die Geschwindigkeit, mit der ein Prozessfortschritt durch die Menge und Geschwindigkeit des verfügbaren Caches begrenzt wird. Eine Aufgabe, die einfach mehr Daten verarbeitet, als in den Cache passt, wird an den Cache gebunden.

I / O Bound wäre langsamer als Memory Bound wäre langsamer als Cache Bound wäre langsamer als CPU Bound.

Die Lösung für die E / A-Bindung besteht nicht unbedingt darin, mehr Speicher zu erhalten. In einigen Situationen kann der Zugriffsalgorithmus auf die Einschränkungen von E / A, Speicher oder Cache ausgelegt sein. Siehe Cache Oblivious Algorithms .

Sanjaya R.
quelle
71

Multithreading

In dieser Antwort werde ich einen wichtigen Anwendungsfall für die Unterscheidung zwischen CPU- und E / A-gebundener Arbeit untersuchen: beim Schreiben von Multithread-Code.

Beispiel für eine RAM-E / A-Bindung: Vektorsumme

Stellen Sie sich ein Programm vor, das alle Werte eines einzelnen Vektors summiert:

#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]

Die Parallelisierung durch gleichmäßige Aufteilung des Arrays für jeden Ihrer Kerne ist auf gängigen modernen Desktops von begrenztem Nutzen.

Auf meinem Ubuntu 19.04, Lenovo ThinkPad P51-Laptop mit CPU: Intel Core i7-7820HQ-CPU (4 Kerne / 8 Threads), RAM: 2x Samsung M471A2K43BB1-CRC (2x 16GiB) erhalte ich folgende Ergebnisse:

Geben Sie hier die Bildbeschreibung ein

Plotdaten .

Beachten Sie jedoch, dass zwischen den Läufen große Unterschiede bestehen. Aber ich kann die Array-Größe nicht weiter erhöhen, da ich bereits bei 8 GB bin und heute nicht in der Stimmung für Statistiken über mehrere Läufe hinweg bin. Dies schien jedoch ein typischer Lauf zu sein, nachdem viele manuelle Läufe durchgeführt wurden.

Benchmark-Code:

Ich kenne nicht genug Computerarchitektur, um die Form der Kurve vollständig zu erklären, aber eines ist klar: Die Berechnung wird nicht 8x schneller als naiv erwartet, da ich alle meine 8 Threads verwende! Aus irgendeinem Grund waren 2 und 3 Threads das Optimum, und das Hinzufügen von mehr macht die Dinge nur viel langsamer.

Vergleichen Sie dies mit CPU-gebundener Arbeit, die tatsächlich achtmal schneller wird: Was bedeuten "real", "user" und "sys" in der Ausgabe von Zeit (1)?

Der Grund dafür ist, dass alle Prozessoren einen einzigen Speicherbus gemeinsam nutzen, der mit dem RAM verbunden ist:

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

So wird der Speicherbus schnell zum Engpass, nicht zur CPU.

Dies geschieht, weil das Hinzufügen von zwei Zahlen einen einzelnen CPU-Zyklus erfordert und das Lesen von Speichern in der Hardware von 2016 etwa 100 CPU-Zyklen dauert .

Die CPU-Arbeit pro Byte der Eingabedaten ist also zu gering, und wir nennen dies einen E / A-gebundenen Prozess.

Die einzige Möglichkeit, diese Berechnung weiter zu beschleunigen, besteht darin, einzelne Speicherzugriffe mit neuer Speicherhardware, z. B. Mehrkanalspeicher , zu beschleunigen .

Ein Upgrade auf einen schnelleren CPU-Takt wäre beispielsweise nicht sehr nützlich.

Andere Beispiele

So finden Sie heraus, ob Sie CPU- oder E / A-gebunden sind

Nicht-RAM-E / A gebunden wie Festplatte, Netzwerk : ps aux, dann prüfen, ob CPU% / 100 < n threads. Wenn ja, sind Sie an die E / A gebunden, z. B. readwarten Blockierungen nur auf Daten, und der Scheduler überspringt diesen Prozess. Verwenden Sie dann weitere Tools sudo iotop, um zu entscheiden, welches E / A genau das Problem ist.

Wenn die Ausführung schnell ist und Sie die Anzahl der Threads parametrisieren, können Sie leicht erkennen, timedass sich die Leistung verbessert, wenn die Anzahl der Threads für CPU-gebundene Arbeit zunimmt: Was bedeuten "real", "user" und "sys"? die Ausgabe der Zeit (1)?

RAM-IO-gebunden: schwerer zu sagen, da die RAM-Wartezeit in den CPU%Messungen enthalten ist, siehe auch:

Einige Optionen:

GPUs

GPUs haben einen E / A-Engpass, wenn Sie die Eingabedaten zum ersten Mal vom regulären CPU-lesbaren RAM auf die GPU übertragen.

Daher können GPUs nur für CPU-gebundene Anwendungen besser sein als CPUs.

Sobald die Daten jedoch an die GPU übertragen wurden, können diese Bytes schneller verarbeitet werden als die CPU, da die GPU:

  • hat mehr Datenlokalisierung als die meisten CPU-Systeme, sodass auf Daten für einige Kerne schneller zugegriffen werden kann als für andere

  • Nutzt die Datenparallelität und opfert die Latenz, indem nur Daten übersprungen werden, die nicht sofort bearbeitet werden können.

    Da die GPU mit großen parallelen Eingangsdaten arbeiten muss, ist es besser, einfach zu den nächsten verfügbaren Daten zu springen, anstatt darauf zu warten, dass die aktuellen Daten verfügbar sind, und alle anderen Vorgänge zu blockieren, wie dies die CPU meistens tut

Daher kann die GPU schneller sein als eine CPU, wenn Ihre Anwendung:

  • kann stark parallelisiert werden: Verschiedene Datenblöcke können gleichzeitig getrennt behandelt werden
  • erfordert eine ausreichend große Anzahl von Operationen pro Eingabebyte (im Gegensatz zu z. B. einer Vektoraddition, die nur eine Addition pro Byte ausführt)
  • Es gibt eine große Anzahl von Eingabebytes

Diese Entwurfsauswahl zielte ursprünglich auf die Anwendung von 3D-Rendering ab. Die Hauptschritte sind wie folgt unter Was sind Shader in OpenGL und wofür benötigen wir sie?

  • Vertex-Shader: Multiplizieren einer Reihe von 1x4-Vektoren mit einer 4x4-Matrix
  • Fragment-Shader: Berechnen Sie die Farbe jedes Pixels eines Dreiecks basierend auf seiner relativen Position innerhalb des Dreiecks

und so schließen wir, dass diese Anwendungen CPU-gebunden sind.

Mit dem Aufkommen der programmierbaren GPGPU können wir mehrere GPGPU-Anwendungen beobachten, die als Beispiele für CPU-gebundene Operationen dienen:

Siehe auch:

CPython Global Intepreter Lock (GIL)

Als kurze Fallstudie möchte ich auf die Python Global Interpreter Lock (GIL) hinweisen: Was ist die globale Interpreter Lock (GIL) in CPython?

Dieses CPython-Implementierungsdetail verhindert, dass mehrere Python-Threads CPU-gebundene Arbeit effizient nutzen. In den CPython-Dokumenten heißt es:

Details zur CPython-Implementierung: In CPython kann aufgrund der globalen Interpreter-Sperre nur ein Thread Python-Code gleichzeitig ausführen (obwohl bestimmte leistungsorientierte Bibliotheken diese Einschränkung möglicherweise überwinden). Wenn Sie möchten, dass Ihre Anwendung die Rechenressourcen von Mehrkernmaschinen besser nutzt, wird empfohlen, multiprocessingoder zu verwenden concurrent.futures.ProcessPoolExecutor. Threading ist jedoch immer noch ein geeignetes Modell, wenn Sie mehrere E / A-gebundene Aufgaben gleichzeitig ausführen möchten.

Daher haben wir hier ein Beispiel, in dem CPU-gebundener Inhalt nicht geeignet ist und E / A-gebunden ist.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
quelle
1
Mann, wie schaffen Sie es, so kompetent zu sein und so etwas zu schreiben?
Mikayil Abdullayev
1
@ MikayilAbdullayev danke! Ich beantworte normalerweise nur "wichtige Fragen" und komme immer wieder darauf zurück, wenn ich neue relevante Dinge lerne.
Ciro Santilli 13 冠状 病 六四 事件 13
2
Dies verdient mehr Upvotes
31

CPU-gebunden bedeutet, dass das Programm von der CPU oder der Zentraleinheit einen Engpass aufweist, während E / A- gebunden bedeutet, dass das Programm durch E / A oder Eingabe / Ausgabe, wie z. B. Lesen oder Schreiben auf Festplatte, Netzwerk usw., einen Engpass aufweist.

Im Allgemeinen wird bei der Optimierung von Computerprogrammen versucht, den Engpass zu ermitteln und zu beseitigen. Zu wissen, dass Ihr Programm CPU-gebunden ist, hilft, damit Sie nicht unnötig etwas anderes optimieren.

[Und mit "Engpass" meine ich die Sache, die Ihr Programm langsamer macht, als es sonst hätte.]

Chris W. Rea
quelle
21

Eine andere Möglichkeit, dieselbe Idee zu formulieren:

  • Wenn das Beschleunigen der CPU Ihr Programm nicht beschleunigt, ist es möglicherweise an die E / A gebunden.

  • Wenn das Beschleunigen der E / A (z. B. die Verwendung einer schnelleren Festplatte) nicht hilft, ist Ihr Programm möglicherweise an die CPU gebunden.

(Ich habe "kann sein" verwendet, weil Sie andere Ressourcen berücksichtigen müssen. Speicher ist ein Beispiel.)

gimel
quelle
11

Wenn Ihr Programm auf E / A wartet (z. B. Lesen / Schreiben auf der Festplatte oder Lesen / Schreiben im Netzwerk usw.), kann die CPU auch dann andere Aufgaben ausführen, wenn Ihr Programm gestoppt ist. Die Geschwindigkeit Ihres Programms hängt hauptsächlich davon ab, wie schnell E / A-Vorgänge ausgeführt werden können. Wenn Sie die E / A beschleunigen möchten, müssen Sie die E / A beschleunigen.

Wenn Ihr Programm viele Programmanweisungen ausführt und nicht auf E / A wartet, wird es als CPU-gebunden bezeichnet. Wenn Sie die CPU beschleunigen, wird das Programm schneller ausgeführt.

In beiden Fällen besteht der Schlüssel zur Beschleunigung des Programms möglicherweise nicht darin, die Hardware zu beschleunigen, sondern das Programm zu optimieren, um die Menge an E / A oder CPU zu reduzieren, die es benötigt, oder es E / A ausführen zu lassen, während es gleichzeitig CPU-intensiv ist Zeug.

Paul Tomblin
quelle
6

Die E / A-Bindung bezieht sich auf einen Zustand, in dem die Zeit, die zum Abschließen einer Berechnung benötigt wird, hauptsächlich durch die Wartezeit auf den Abschluss von Eingabe- / Ausgabeoperationen bestimmt wird.

Dies ist das Gegenteil einer CPU-gebundenen Aufgabe. Dieser Umstand tritt auf, wenn die Rate, mit der Daten angefordert werden, langsamer ist als die Rate, mit der sie verbraucht werden, oder mit anderen Worten, mehr Zeit für das Anfordern von Daten aufgewendet wird als für die Verarbeitung.

FellyTone84
quelle
6

E / A-gebundene Prozesse: Verbringen Sie mehr Zeit mit E / A als mit Berechnungen, haben Sie viele kurze CPU-Bursts. CPU-gebundene Prozesse: Verbringen Sie mehr Zeit mit Berechnungen, wenige sehr lange CPU-Bursts

dua
quelle
2

Sehen Sie, was Microsoft sagt.

Der Kern der asynchronen Programmierung sind die Task- und Task-Objekte, die asynchrone Operationen modellieren. Sie werden von der asynchronen Funktion unterstützt und warten auf Schlüsselwörter. Das Modell ist in den meisten Fällen ziemlich einfach:

  • Für E / A-gebundenen Code warten Sie auf eine Operation, die eine Aufgabe oder Aufgabe innerhalb einer asynchronen Methode zurückgibt.

  • Bei CPU-gebundenem Code warten Sie auf eine Operation, die in einem Hintergrundthread mit der Task.Run-Methode gestartet wird.

Das Schlüsselwort "Warten" ist der Ort, an dem die Magie geschieht. Es gibt dem Aufrufer die Kontrolle über die Methode, die das Warten ausgeführt hat, und ermöglicht letztendlich, dass eine Benutzeroberfläche reagiert oder ein Dienst elastisch ist.

E / A-gebundenes Beispiel: Herunterladen von Daten von einem Webdienst

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-gebundenes Beispiel: Durchführen einer Berechnung für ein Spiel

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);
};

Die obigen Beispiele haben gezeigt, wie Sie Async verwenden und auf E / A-gebundene und CPU-gebundene Arbeit warten können. Es ist wichtig, dass Sie feststellen können, wann ein Job, den Sie ausführen müssen, E / A- oder CPU-gebunden ist, da dies die Leistung Ihres Codes stark beeinträchtigen und möglicherweise zum Missbrauch bestimmter Konstrukte führen kann.

Hier sind zwei Fragen, die Sie stellen sollten, bevor Sie Code schreiben:

Wird Ihr Code auf etwas "warten", beispielsweise auf Daten aus einer Datenbank?

  • Wenn Ihre Antwort "Ja" lautet, ist Ihre Arbeit E / A-gebunden.

Wird Ihr Code eine sehr teure Berechnung durchführen?

  • Wenn Sie mit "Ja" geantwortet haben, ist Ihre Arbeit CPU-gebunden.

Wenn Ihre Arbeit E / A-gebunden ist, verwenden Sie asynchron und warten Sie ohne Task.Run . Sie sollten die Task Parallel Library nicht verwenden. Der Grund dafür ist im Artikel Async in Depth beschrieben.

Wenn Ihre Arbeit CPU-gebunden ist und Sie Wert auf Reaktionsfähigkeit legen, verwenden Sie Async und warten Sie, aber erzeugen Sie die Arbeit in einem anderen Thread mit Task.Run. Wenn die Arbeit für Parallelität und Parallelität geeignet ist, sollten Sie auch die Task Parallel Library in Betracht ziehen .

Taşyürek Gökşah
quelle
2

Eine Anwendung ist CPU-gebunden, wenn die Leistung von Arithmetik / Logik / Gleitkomma (A / L / FP) während der Ausführung meist nahe an der theoretischen Spitzenleistung des Prozessors liegt (Daten vom Hersteller bereitgestellt und durch die Eigenschaften des Prozessors bestimmt) Prozessor: Anzahl der Kerne, Frequenz, Register, ALUs, FPUs usw.).

Die Peek-Leistung ist in realen Anwendungen sehr schwer zu erreichen, da dies nicht unmöglich ist. Die meisten Anwendungen greifen in verschiedenen Teilen der Ausführung auf den Speicher zu, und der Prozessor führt während mehrerer Zyklen keine A / L / FP-Operationen aus. Dies wird aufgrund der Entfernung zwischen Speicher und Prozessor als Von-Neumann-Einschränkung bezeichnet .

Wenn Sie sich der CPU-Spitzenleistung nähern möchten, besteht eine Strategie darin, zu versuchen, die meisten Daten im Cache-Speicher wiederzuverwenden, um zu vermeiden, dass Daten aus dem Hauptspeicher benötigt werden. Ein Algorithmus, der diese Funktion ausnutzt, ist die Matrix-Matrix-Multiplikation (wenn beide Matrizen im Cache-Speicher gespeichert werden können). Dies geschieht, weil Sie, wenn die Matrizen eine Größe n x nhaben, 2 n^3Operationen ausführen müssen, bei denen nur 2 n^2FP-Datenzahlen verwendet werden. Andererseits ist die Matrixaddition beispielsweise eine weniger CPU-gebundene oder mehr speichergebundene Anwendung als die Matrixmultiplikation, da nur n^2FLOPs mit denselben Daten erforderlich sind .

In der folgenden Abbildung sind die FLOPs dargestellt, die mit einem naiven Algorithmus für die Matrixaddition und die Matrixmultiplikation in einem Intel i5-9300H erhalten wurden:

FLOPs Vergleich zwischen Matrixaddition und Matrixmultiplikation

Beachten Sie, dass die Leistung der Matrixmultiplikation erwartungsgemäß größer ist als die Matrixaddition. Diese Ergebnisse können durch Ausführen reproduziert werden test/gemmund test/mataddsind in diesem Repository verfügbar .

Ich schlage auch vor, das Video von J. Dongarra über diesen Effekt zu sehen.

GG1991
quelle
1

E / A-gebundener Prozess: - Wenn der größte Teil der Lebensdauer eines Prozesses im E / A-Status verbracht wird, ist der Prozess ai / o-gebundener Prozess. Beispiel: -Calculator, Internet Explorer

CPU-gebundener Prozess: - Wenn der größte Teil der Prozesslebensdauer in CPU verbracht wird, handelt es sich um einen CPU-gebundenen Prozess.

K.Abhishek
quelle
8
Wie wäre der Rechner ein IO-gebundener Prozess? Sicher wäre es CPU-gebunden. Wenn Ihr Rechner die meiste Zeit damit verbringt, durch den Zugriff auf das Netzwerk oder die Festplatte blockiert zu werden, würde ich vorschlagen, dass etwas damit nicht stimmt.
Rickerbh
6
Ich dachte, das Taschenrechner-Beispiel sei klar: Meistens wartet es darauf, dass der Benutzer eine Taste drückt, und wartet daher auf E / A.
PSP
1
@psp ist richtig, aber das Taschenrechner-Beispiel ist aufgrund seines Namens "Taschenrechner" immer noch oberflächlich schwer als io-gebunden zu sehen. Das bedeutet, dass der Hauptzweck des Programms darin besteht, lange CPU-Berechnungen durchzuführen. Wenn Sie sich jedoch Ihren Taschenrechner auf Ihrem Desktop ansehen, ist dies sehr einfach und führt nur Berechnungen durch, deren Ausführung Nanosekunden dauert. Daher wartet es die meiste Zeit auf Benutzereingaben, bei denen es sich um E / A handelt.
Calicoder