Verwendet cat Lazy Evaluation?

Verwendet cat Lazy Evaluation?

Bei der Verwendung von Rohren zum Beispiel

sudo cat /dev/sda | strings | less

Ich kann mich in den Stringzeilen meines SDA-Geräts bewegen. Aber werden die Inhalte des SDA-Geräts vollständig geladen und in den Ausgabestream von cat ausgegeben? Oder werden die neuen Zeilen ausgewertet, wenn ein Programm eine Ausgabe von cat anfordert? (d. h. ich drücke „J“ auf dem Less-Pager)

Antwort1

Dies hat mehr mit dem Wie zu tun lessals mit dem Wie catoder stringsArbeiten.

Der catBefehl überträgt Daten nur an seine Standardausgabe und wird blockiert, wenn der Pipe-Puffer zwischen ihm und stringsvoll ist und niemand liest. catführt selbst nur minimale Pufferung durch und der Pipe-Puffer ist normalerweise klein.

Dies gilt auch für strings. Es verarbeitet die Daten von catund blockiert, wenn lessdie von ihm erzeugten Daten nicht gelesen werden strings.

lesspuffert seine Eingabe, damit Sie in den angezeigten Daten vor- und zurückblättern können. Wenn Sie zur nächsten Seite scrollen, lessliest mehr Daten aus stringsseinem Puffer. Wenn Sie nicht vorwärts scrollen, liest meiner Meinung nach lessnur eine begrenzte Datenmenge (und wird daher stringsblockiert cat, wenn Sie nicht vorwärts scrollen).

Wenn Sie eine große Datenmenge an weiterleiten less, wird für diese Pufferung ziemlich viel Speicher verwendet.WennSie beschließen, alles bis zum Ende durchzulesen less.

Es gibt eine Option -B, die die Speichermenge, die zum Puffern verwendet wird, auf 64 Kilobyte begrenzt (oder auf die von Ihnen mit der -bOption angegebene Menge). Wenn Sie die Puffergröße auf diese Weise begrenzen, können Sie nicht weiter zurückblättern, als der angegebene Pufferspeicherplatz aufnehmen kann. Sie können aber auch große Datenmengen lesen, ohne dass lessder Speicher ausgeht.

Siehe auch man lessauf Ihrem System.

Antwort2

Pipes haben begrenzten Pufferspeicherplatz, und wenn ein Pipe-Reader (wie lessin Ihrem Beispiel) keine weiteren Daten aus der Pipe liest, wird der Writer nach dem Füllen des Puffers blockiert. Dies wirkt sich auf den stringsBefehl aus, der wiederum den Befehl blockiert, catnachdem seine Pipe voll ist.

Natürlich kann der catBefehl nicht den gesamten Inhalt des SDA-Geräts in den Hauptspeicher lesen. Wenn also Blöcke geändert werden, die noch nicht von ihm gelesen wurden, catwerden die geänderten Inhalte angezeigt.

Antwort3

Sowohl catals auch stringsund die meisten ähnlichen Dienstprogramme¹ lesen jeweils eine kleine Eingabe, verarbeiten sie, lesen dann weitere Eingaben usw. In Ihrem Fall catliest es also nur das , was lessangezeigt wird, plus ein wenig mehr, was unterwegs ist.

Genauer gesagt catist die grundlegende Funktionsweise:

  • Reservieren Sie einige Kilobyte Speicher zur Verwendung als Puffer.
  • Es stehen noch weitere Eingabemöglichkeiten zur Verfügung:
    • Liest bis zu N Bytes an Eingaben in den Puffer. (Dadurch werden Daten überschrieben, die in einem vorherigen Zyklus ausgegeben wurden.)
    • Schreibt den Pufferinhalt in die Ausgabe.

Der Schreibvorgang blockiert, bis ein Platz zum Kopieren der Ausgabe vorhanden ist. Wenn die Ausgabe einer Pipe erfolgt, verbraucht die Pipe selbst ein wenig Speicher im Kernel, was alsRohrpuffer. Wenn dieser voll ist, catwird der Schreibversuch blockiert, wenn versucht wird, in die Pipe zu schreiben, bis Platz ist. Im Pipe-Puffer kann Platz sein, wenn der Prozess am Leseende der Pipe einige Daten liest.

Das stringsProgramm funktioniert genauso wie cat, mit dem Unterschied, dass es nicht die gesamte Eingabe kopiert, sondern nur ausgewählte Teile.

Das lessProgramm funktioniert etwas anders: Es behält alles, was es liest, im Speicher. Es recycelt seinen Puffer nicht, sondern vergrößert ihn, solange weitere Eingaben eingehen. Der Leseteil ist jedoch insofern ähnlich, als dass er lessDaten nur liest, wenn er sie benötigt: Er liest nur bis zur letzten angezeigten Zeile und zusätzlich noch ein wenig mehr, falls verfügbar.

Wenn Sie also ausführen , besteht sudo cat /dev/sda | strings | lessder Lesevorgang aus Folgendem:/dev/sda

  • Daten, die lessbereits angezeigt wurden (oder vorbeigescrollt sind).
  • Bis zu einigen KB an Daten, die lessgelesen, aber noch nicht angezeigt wurden.
  • Bis zu einigen kB im Pipe-Puffer zwischen stringsund less.
  • Bis zu einigen kB im Speicher von strings.
  • Bis zu einigen kB im Pipe-Puffer zwischen catund strings.
  • Bis zu einigen kB im Speicher von cat.

Sie können beobachten, wann jedes Programm Daten liest und schreibt, indem Sie seine Systemaufrufe verfolgen:

sudo strace -e read,write -o cat.strace cat /dev/sda | strace -e read,write -o cat.strace strings | strace -e read,write -o less.strace less

und beobachten Sie die *.straceDateien. Sie können auch überprüfen, wie viel catgelesen wurde, indem Sie den Dateioffset überprüfen, beispielsweise mit lsof -p1234oder mit head /proc/1234/fdinfo/0wobei 1234die Prozess-ID von ist cat.

¹ Die wichtigste Ausnahme unter den grundlegenden Textverarbeitungsprogrammen ist , sortdas keine Ausgabe ausgeben kann, bis es die gesamte Eingabe gelesen hat: Nach allem, was es weiß, kann die erste Ausgabezeile durchaus auch die letzte Eingabezeile sein, die es erreicht.

Antwort4

Auf einigen Systemen (z. B. MS-Dos) wird die Pipe implementiert, indem die Ausgabe des ersten Befehls in eine Datei kopiert und dann der zweite Befehl ausgeführt wird, um aus dieser Datei zu lesen. Unix macht das nicht so.

Unter Unix ist es wie eine Produktionsstraße. Jede Stufe arbeitet gleichzeitig, liest Eingaben und erzeugt Ausgaben. Wenn Prozess A schneller produziert als Prozess B verbraucht, dann gibt es einen Lagerbestand zwischen Prozess A und B. Wenn dieser zu groß ist (½ KiB bis 4 KiB), wird Prozess A angehalten. Wenn B keinen Lagerbestand mehr zu verarbeiten hat, wird B angehalten. Prozesse werden angehalten und wieder aufgenommen, um die Lagerbestände niedrig zu halten.

Der Code in diesen Programmen kümmert sich um nichts davon. Er liest nur die Eingabe und schreibt die Ausgabe. Wenn er versucht zu lesen, bevor Daten verfügbar sind, oder versucht zu schreiben, bevor der nächste Prozess bereit ist, wird er vom Betriebssystem angehalten, bis er bereit ist.

Wenn nichts mehr zu lesen ist (und nichts mehr unterwegs ist), erhält der Reader ein Dateiende und wird beendet. Dies wiederum löst im nächsten Prozess ein Dateiende aus.

verwandte Informationen