2 Punkte von GN⁺ 2024-11-30 | 1 Kommentare | Auf WhatsApp teilen

Warum Pipes „hängen“: Buffering

  • Problembeschreibung: Wenn man den Befehl tail -f /some/log/file | grep thing1 | grep thing2 ausführt, um in einer Log-Datei nach einer bestimmten Ausgabe zu suchen, kann es vorkommen, dass keine Ausgabe erscheint, wenn neue Log-Zeilen nur langsam hinzukommen. Es wirkt dann, als ob die Pipe hängt, tatsächlich schreibt das Programm die Daten aber einfach noch nicht in die Pipe.

Ursachen des Bufferings

  • Warum gepuffert wird: Es ist üblich, dass Programme Daten puffern, bevor sie sie in eine Pipe oder Datei schreiben. Das dient der Performance, weil die Ausgabe nicht sofort bei jeder Zeile geschrieben wird, sondern erst, wenn eine bestimmte Datenmenge gesammelt wurde.
  • Beispiel: grep thing1 speichert passende Daten, bis 8 KB zusammengekommen sind, wodurch die Ausgabe verzögert erscheinen kann.

Beim Schreiben ins Terminal wird nicht gepuffert

  • Unterschied zwischen Terminal und Pipe: grep verwendet Line Buffering, wenn die Ausgabe an ein Terminal geht, aber Block Buffering, wenn sie an eine Pipe geht. Das wird über die Funktion isatty entschieden.

Befehle mit und ohne Buffering

  • Befehle ohne Buffering: tail, cat, tee usw. puffern nicht.
  • Befehle mit Buffering: grep, sed, awk, tcpdump, jq, tr, cut usw. puffern, bei einigen lässt sich das mit bestimmten Flags deaktivieren.

Standardmäßiges Ausgabebuffering in Programmiersprachen

  • Sprachen mit Buffering: C, Python, Ruby, Perl usw. puffern die Ausgabe standardmäßig, lassen sich aber auf bestimmte Weise entsprechend konfigurieren.

Verlust des Buffer-Inhalts bei Ctrl-C

  • Problembeschreibung: Wenn man Ctrl-C drückt, geht der Inhalt des Buffers verloren. Der Grund ist, dass zuerst das Signal SIGINT zugestellt wird.
  • Lösung: Wenn man die PID von tcpdump ermittelt und kill -TERM $PID ausführt, kann der Buffer geleert werden.

Auch beim Umleiten in eine Datei wird gepuffert

  • Dateiumleitung: Auch bei einer Umleitung in eine Datei tritt Buffering auf, allerdings kommt es dabei nicht zum Problem des Buffer-Verlusts durch Ctrl-C.

Verschiedene Wege, Buffering zu vermeiden

  • Lösung 1: Ein Programm ausführen, das schnell beendet wird.
  • Lösung 2: Das Flag --line-buffered von grep verwenden.
  • Lösung 3: awk verwenden.
  • Lösung 4: stdbuf verwenden.
  • Lösung 5: unbuffer verwenden.

Umgebungsvariablen zum Deaktivieren von Buffering

  • Idee: Es wäre praktisch, wenn es eine standardisierte Umgebungsvariable wie PYTHON_UNBUFFERED gäbe. Vorgeschlagen wird eine Variable wie NO_BUFFER.

Ausgelassene Inhalte

  • Ausgelassene Themen: Der Unterschied zwischen Line Buffering und vollständigem Unbuffering, Unterschiede beim Buffering von stderr und stdout sowie das Buffering des TTY-Treibers im Betriebssystem.

1 Kommentare

 
GN⁺ 2024-11-30
Hacker-News-Kommentare
  • Gepufferter Zugriff sollte nach einer bestimmten Anzahl von Bytes oder nach Ablauf einer gewissen Zeit geleert werden. Das ist ein gängiger Ansatz zur Lösung ähnlicher Probleme bei Hardware-Schnittstellen

    • Eine Bibliothek, die im User Space puffert, sollte beim ersten Puffern von Daten einen geeigneten Timer setzen
    • Der Timeout-Parameter sollte als Argument übergeben werden oder etwas unterhalb menschlicher Zeitskalen liegen, proportional zur Bandbreite bzw. zum Schwellenwert sein oder proportional zum Flush-Overhead
    • Das gilt sowohl fürs Schreiben als auch fürs Lesen und kann je nach Datenkanal unterschiedlich sein
  • Wenn die CPU des gesamten Systems in den Idle-Zustand geht, möchte ich alle Puffer leeren

    • Pufferung ist im Allgemeinen eine Technik zum Einsparen von CPU-Ressourcen
    • Wenn die CPU in den Idle-Zustand geht, sollte ein Signal an alle Prozesse gesendet werden: „Leert eure Puffer“
  • Ich arbeite seit über 20 Jahren mit NIX-Systemen, vergesse Pufferungsprobleme aber immer wieder

  • Ich nutze Unix seit über 35 Jahren, habe aber nie vollständig verstanden, wie Pufferung funktioniert. Diese Erklärung war hilfreich

  • Hier werden „ungepuffert“ und „zeilengepuffert“ verwechselt

    • Ungepufferte Ausgabe kann die Performance verschlechtern und falsche Ausgaben erzeugen, wenn mehrere Quellen in dieselbe Pipe schreiben
    • Zeilenpufferung ist der Standard bei Terminals und eignet sich gut für Pipes
  • Puffer existieren, weil das Schreiben in einen Puffer im Vergleich zur Ausgabe auf dem Bildschirm relativ sehr langsam ist

    • Das ist ein häufiges Problem bei der Arbeit mit UART, und es gibt verschiedene Lösungen
    • Es gibt unterschiedliche Ansätze wie Sonderzeichen, längenbasierte Verfahren oder zeitbasierte Verfahren
  • Beim Drücken von Ctrl-C kann der Inhalt des Puffers verloren gehen

    • Ich hätte erwartet, dass die meisten Programme bei SIGINT ihre Puffer leeren
  • Ich habe unter Unix Pufferungsprobleme erlebt, und nicht alle 'awk'-Implementierungen verhalten sich gleich

  • Ich habe das Wortspiel mit der eingefrorenen Pipe wohl verpasst