Gepuffert gegen ungepuffertes IO


83

Ich habe erfahren, dass E / A in Programmen standardmäßig gepuffert sind, dh sie werden von einem temporären Speicher an das anfordernde Programm gesendet. Ich verstehe, dass das Puffern die E / A-Leistung verbessert (möglicherweise durch Reduzieren von Systemaufrufen). Ich habe Beispiele für das Deaktivieren der Pufferung gesehen, wie setvbufin C. Was ist der Unterschied zwischen den beiden Modi und wann sollte einer über dem anderen verwendet werden?

Antworten:


123

Sie möchten eine ungepufferte Ausgabe, wenn Sie sicherstellen möchten, dass die Ausgabe geschrieben wurde, bevor Sie fortfahren. Ein Beispiel ist ein Standardfehler unter einer C-Laufzeitbibliothek - dieser ist normalerweise standardmäßig ungepuffert. Da Fehler (hoffentlich) selten sind, möchten Sie sie sofort kennen. Auf der anderen Seite, die Standardausgabe ist einfach gepuffert , weil es dort angenommen , durchläuft es weit mehr Daten sein wird.

Ein weiteres Beispiel ist eine Protokollierungsbibliothek. Wenn Ihre Protokollnachrichten in Puffern in Ihrem Prozess gespeichert sind und Ihr Prozess den Kern entleert, besteht eine sehr gute Chance, dass die Ausgabe niemals geschrieben wird.

Darüber hinaus werden nicht nur Systemaufrufe minimiert, sondern auch Festplatten-E / A. Angenommen, ein Programm liest eine Datei byteweise. Bei ungepufferter Eingabe gehen Sie für jedes Byte auf die (relativ sehr langsame) Festplatte, obwohl sie wahrscheinlich ohnehin einen ganzen Block einlesen muss (die Festplattenhardware selbst verfügt möglicherweise über Puffer, aber Sie gehen immer noch zum Festplattencontroller Dies wird langsamer sein als der In-Memory-Zugriff.

Durch das Puffern wird der gesamte Block sofort in den Puffer eingelesen, und die einzelnen Bytes werden Ihnen aus dem (speicherinternen, unglaublich schnellen) Pufferbereich zugestellt.

Beachten Sie, dass die Pufferung viele Formen annehmen kann, wie im folgenden Beispiel:

+-------------------+-------------------+
| Process A         | Process B         |
+-------------------+-------------------+
| C runtime library | C runtime library | C RTL buffers
+-------------------+-------------------+
|               OS caches               | Operating system buffers
+---------------------------------------+
|      Disk controller hardware cache   | Disk hardware buffers
+---------------------------------------+
|                   Disk                |
+---------------------------------------+

Die Grafik ist wunderbar. Erwähnenswert ist, dass sich der FILEinterne Puffer eines Objekts (eines Streams) vollständig von einem fgetserforderlichen Pufferparameter unterscheidet. Das hat mich nur stundenlang verwirrt, bevor ich einen Code geschrieben habe, um es herauszufinden. QAQ
Rick

34

Sie möchten eine ungepufferte Ausgabe, wenn Sie bereits eine große Folge von Bytes zum Schreiben auf die Festplatte bereit haben, und möchten eine zusätzliche Kopie in einen zweiten Puffer in der Mitte vermeiden .

Gepufferte Ausgabestreams sammeln Schreibergebnisse in einem Zwischenpuffer und senden sie nur dann an das Betriebssystem-Dateisystem, wenn sich genügend Daten angesammelt haben (oder flush()angefordert werden). Dies reduziert die Anzahl der Dateisystemaufrufe. Da Dateisystemaufrufe auf den meisten Plattformen teuer sein können (im Vergleich zu kurzen memcpy), ist die gepufferte Ausgabe ein Nettogewinn, wenn eine große Anzahl kleiner Schreibvorgänge ausgeführt wird. Die ungepufferte Ausgabe ist im Allgemeinen besser, wenn Sie bereits große Puffer zum Senden haben. Durch das Kopieren in einen Zwischenpuffer wird die Anzahl der Betriebssystemaufrufe nicht weiter reduziert, und es wird zusätzliche Arbeit eingeführt.

Die ungepufferte Ausgabe hat nichts damit zu tun, dass Ihre Daten die Festplatte erreichen. Diese Funktionalität wird von flush()gepufferten und ungepufferten Streams bereitgestellt und funktioniert sowohl für gepufferte als auch für ungepufferte Streams. Ungepufferte E / A-Schreibvorgänge garantieren nicht, dass die Daten die physische Festplatte erreicht haben. Das Betriebssystem-Dateisystem kann eine Kopie Ihrer Daten unbegrenzt aufbewahren und sie niemals auf die Festplatte schreiben, wenn dies gewünscht wird. Es ist nur erforderlich, es beim Aufrufen auf die Festplatte zu übertragen flush(). (Beachten Sie, dass close()in flush()Ihrem Namen anrufen wird ).


Wird der Aufruf flush()garantieren, dass er auf die Festplatte geschrieben wurde? Ich dachte, das würde es nur an den Puffer der Festplatte weitergeben.
Jrdioko

2
Sie müssen O_SYNCsicherstellen, dass Schreibvorgänge garantiert werden.
Moshbear

Ungepufferte E / A ks über das Schreiben auf die Festplatte. Daher der Begriff ungepuffert (kein Zwischenpuffer, sondern direkt auf die Festplatte geschrieben) für Winapi, den Sie CreateFile mit FILE_FLAG_NO_BUFFERING und FILE_FLAG_WRITE_THROUGH aufrufen, um sicherzustellen, dass die Daten nach jedem Schreibvorgang direkt persistieren. Für einige andere Betriebssysteme weiß es nicht.
Martin Kosicky
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.