Streaming-Pipelines und Named Pipes für hohen Durchsatz
Verwenden Sie FIFOs und Prozesssubstitution, um Daten ohne Zwischendateien zwischen Verarbeitungsschritten zu streamen.
Streaming-Pipelines und Named Pipes für hohen Durchsatz ist eine kostenlose Linux Command Line & Bash Scripting Mastery-Lektion auf CoddyKit. Dies ist Lektion 4 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Linux Command Line & Bash Scripting Mastery-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Warum temporäre Dateien den Durchsatz verringern
Wenn Sie Befehle wie sort file.txt > tmp.txt && uniq tmp.txt > result.txt verketten, zahlen Sie einen versteckten Preis: Schreibvorgänge auf die Festplatte, Lesevorgänge von der Festplatte, und die Pipeline wartet, bis die erste Stufe vollständig abgeschlossen ist, bevor die nächste beginnt.
Streaming-Pipelines vermeiden diesen Aufwand. Die Daten fließen stufenweise und nebenläufig direkt vom Erzeuger zum Verbraucher im Speicher. Das ist die grundlegende Idee hinter Unix-Pipes — und Named Pipes (FIFOs) führen sie noch weiter.
- Anonyme Pipe (
|): verbindet zwei direkt aufeinanderfolgende Befehle in derselben Shell-Zeile. - Named Pipe (FIFO): eine spezielle Datei im Dateisystem, über die voneinander unabhängige Prozesse Daten aneinander streamen können.
- Prozesssubstitution: ermöglicht es einem Befehl, die Ausgabe eines anderen Befehls so zu behandeln, als wäre sie eine Datei.
In dieser Lektion erfahren Sie, wie Sie alle drei Möglichkeiten einsetzen, um den Durchsatz in praxisnahen Bash-Workflows zu maximieren.
Aufbau einer Streaming-Pipeline
Eine anonyme Pipe verbindet die stdout-Ausgabe eines Prozesses mit der stdin-Eingabe des nächsten. Der Kernel lässt beide Prozesse gleichzeitig laufen und verwendet dafür einen fest dimensionierten Puffer im Arbeitsspeicher (unter Linux typischerweise 64 KB).
Die entscheidende Erkenntnis lautet: Die Pipeline ist so schnell wie ihre langsamste Stufe. Ist der Erzeuger schneller, wird er bei einem vollen Puffer blockiert. Ist der Verbraucher schneller, wird er bei einem leeren Puffer blockiert. Dieser Rückstau ist eine kostenlose, automatische Flusssteuerung.
Das folgende Beispiel zählt eindeutige IP-Adressen in einem großen Zugriffsprotokoll, ohne jemals eine temporäre Datei zu schreiben. Jede Stufe läuft nebenläufig:
#!/usr/bin/env bash
# Stream a 2 GB access log — all stages run in parallel
grep '"GET' /var/log/nginx/access.log \
| awk '{print $1}' \
| sort \
| uniq -c \
| sort -rn \
| head -20Named Pipes mit mkfifo erstellen
Eine Named Pipe (FIFO — First In, First Out) wird mit mkfifo erstellt. Sie erscheint im Dateisystem wie eine normale Datei, aber in sie geschriebene Daten werden niemals auf der Festplatte gespeichert — sie fließen direkt zum lesenden Prozess.
Wichtige Verhaltensweisen:
- Ein Schreibvorgang in eine FIFO blockiert, bis ein Leser sie öffnet, und umgekehrt.
- Der FIFO-Eintrag bleibt im Dateisystem bestehen; Sie müssen ihn anschließend mit
rmlöschen. - Mehrere Schreiber sind zulässig, aber ihre Reihenfolge ist nicht garantiert.
Im folgenden Beispiel komprimiert ein Erzeuger Daten in eine FIFO, während ein Verbraucher sie gleichzeitig in S3 hochlädt — eine temporäre Datei ist nicht erforderlich.
#!/usr/bin/env bash
mkfifo /tmp/stream_pipe
# Producer: compress in background
gzip -c /var/log/syslog > /tmp/stream_pipe &
# Consumer: read from FIFO (runs in foreground)
wc -l < /tmp/stream_pipe
wait
rm /tmp/stream_pipeProzesssubstitution: Einen Befehl als Datei behandeln
Prozesssubstitution verwendet die Syntax <(command) oder >(command). Bash erstellt im Hintergrund eine FIFO (oder eine /dev/fd/N-Datei beziehungsweise einen Dateideskriptor) und übergibt den Pfad an den äußeren Befehl.
Das ist besonders nützlich, wenn ein Tool ein Argument mit einem Dateinamen statt stdin erwartet. Ohne Prozesssubstitution bräuchten Sie eine temporäre Datei; mit Prozesssubstitution streamen Sie direkt.
<(cmd)— der äußere Befehl liest die Ausgabe von cmd.>(cmd)— der äußere Befehl schreibt in die Eingabe von cmd.
#!/usr/bin/env bash
# diff two sorted streams without creating temp files
diff <(sort /etc/passwd) <(sort /etc/group)
# Compare live command output against a baseline
diff <(ls /usr/bin | sort) <(cat ~/bin_baseline.txt | sort)Tee: Einen Stream auf mehrere Verbraucher aufteilen
tee liest stdin und schreibt die Daten sowohl nach stdout als auch in eine oder mehrere Dateien. In Kombination mit Prozesssubstitution können Sie einen einzelnen Stream gleichzeitig auf mehrere Verarbeitungspipelines verteilen — ganz ohne Festplattenzugriffe.
Dieses Muster ist nützlich, wenn Sie beispielsweise Rohdaten protokollieren und gleichzeitig verarbeiten möchten.
#!/usr/bin/env bash
# Generate 100000 random numbers, then simultaneously:
# 1. compute the sum
# 2. find the maximum
# 3. count lines (saved to a variable)
seq 1 100000 \
| tee >(awk '{s+=$1} END{print "Sum:", s}') \
>(awk 'BEGIN{m=0} $1>m{m=$1} END{print "Max:", m}') \
| wc -l | xargs echo "Count:"Fan-out-Muster: Ein Erzeuger, viele Verbraucher
Wenn eine einzelne Datenquelle mehrere unabhängige Verbraucher versorgen soll, kombinieren Sie tee mit mehreren >()-Prozesssubstitutionen. Jeder Verbraucher erhält den vollständigen Stream und läuft nebenläufig.
Dadurch muss die Quelldatei nicht mehrfach gelesen werden. Bei einer 10-GB-Datei ist der Unterschied enorm — ein Festplatten-Lesevorgang statt N Lesevorgängen.
#!/usr/bin/env bash
# Read a large CSV once; simultaneously:
# - count rows
# - extract column 2 to a file
# - pass column 3 to a stats script
cat large_data.csv \
| tee \
>(wc -l > /tmp/row_count.txt) \
>(cut -d',' -f2 > /tmp/col2.txt) \
>(cut -d',' -f3 | awk '{sum+=$1} END{print sum}' > /tmp/col3_sum.txt) \
> /dev/null
echo "Rows:" $(cat /tmp/row_count.txt)
echo "Col3 sum:" $(cat /tmp/col3_sum.txt)Fan-in-Muster: Viele Erzeuger, ein Verbraucher
Das Gegenstück zu Fan-out ist Fan-in: Mehrere unabhängige Quellen streamen in einen einzelnen Verbraucher. Named FIFOs machen dies unkompliziert.
Ein häufiger Anwendungsfall ist das Zusammenführen von Protokollstreams mehrerer Server in Echtzeit oder das Aggregieren von Teilergebnissen paralleler Worker.
Beachten Sie, dass der Verbraucher bei mehreren Schreibern eine vermischte Ausgabe erhält — das ist für zeilenorientierte Daten geeignet, bei denen jede Zeile in sich abgeschlossen ist. Wenn die Reihenfolge relevant ist, müssen Sie sie jedoch selbst verwalten.
#!/usr/bin/env bash
mkfifo /tmp/fanin_pipe
# Three producers write concurrently into the same FIFO
for host in web1 web2 web3; do
ssh "$host" 'tail -n 500 /var/log/app.log' > /tmp/fanin_pipe &
done
# Single consumer reads all merged output
grep 'ERROR' /tmp/fanin_pipe | sort | uniq -c | sort -rn
wait
rm /tmp/fanin_pipemkfifo für parallele Komprimierung verwenden
Eine der praktischsten Anwendungen von FIFOs ist die parallele Komprimierung. Tools wie pigz (paralleles gzip) oder pbzip2 lesen einen Stream; Sie können die Rohdaten direkt weiterleiten, ohne zunächst eine unkomprimierte Datei anzulegen.
Das folgende Muster archiviert ein Verzeichnis, komprimiert es mit allen CPU-Kernen und streamt das Ergebnis gleichzeitig an einen Remote-Host:
#!/usr/bin/env bash
# Tar + parallel compress + stream to remote — no temp files
# Requires: pigz (parallel gzip)
tar cf - /data/large_dir \
| pigz -p 4 \
| ssh backup-host 'cat > /backups/large_dir.tar.gz'
# Verify the remote file exists
ssh backup-host 'ls -lh /backups/large_dir.tar.gz'Puffergröße und Blockierung steuern
Pipes verfügen über einen Kernel-Puffer (normalerweise 64 KB). Wenn der Puffer voll ist, blockiert der Schreiber; wenn er leer ist, blockiert der Leser. Normalerweise ist das erwünscht, aber in manchen Fällen führt die Blockierung zu einem Deadlock.
Deadlock-Risiko: Wenn Prozess A in FIFO1 schreibt und aus FIFO2 liest, während Prozess B in FIFO2 schreibt und aus FIFO1 liest, können beide blockieren, weil jeder darauf wartet, dass der andere zuerst Daten entnimmt.
Lösungen:
- Führen Sie mindestens eine Seite im Hintergrund (
&) aus, damit sie die Shell nicht blockiert. - Verwenden Sie
mbufferoderpv, um zwischen den Stufen einen größeren Puffer im Arbeitsspeicher einzufügen. - Verwenden Sie
pv -q -B 128m, um einen 128-MB-Puffer einzufügen und so Durchsatzspitzen auszugleichen.
#!/usr/bin/env bash
# pv adds a 64 MB buffer and shows throughput
# Useful when producer and consumer have bursty speeds
dd if=/dev/urandom bs=1M count=200 \
| pv -B 64m \
| gzip \
| wc -cPraxisbeispiel: Aggregator für Protokolle in Echtzeit
Hier ist ein vollständiges, realistisches Muster: Mehrere Protokolldateien mit tail verfolgen, die Streams über eine Named Pipe zusammenführen, nach Fehlern filtern und eine Live-Zusammenfassung schreiben — alles ohne temporäre Dateien und mit gleichzeitig laufenden Stufen.
Eine solche Pipeline würde als Hintergrundskript zur Überwachung auf einem Produktionsserver ausgeführt.
#!/usr/bin/env bash
FIFO=/tmp/log_aggregator
mkfifo "$FIFO"
cleanup() { rm -f "$FIFO"; }
trap cleanup EXIT INT TERM
# Fan-in: tail multiple logs into the FIFO
tail -F /var/log/syslog /var/log/auth.log > "$FIFO" &
TAIL_PID=$!
# Consumer: filter and timestamp errors in real time
grep --line-buffered -i 'error\|fail\|crit' "$FIFO" \
| while IFS= read -r line; do
printf '[%s] %s\n' "$(date '+%H:%M:%S')" "$line"
done
kill "$TAIL_PID" 2>/dev/nullPipelines und temporäre Dateien vergleichen
Mit time können Sie den tatsächlichen Durchsatzunterschied zwischen dem Streaming-Ansatz und dem Ansatz mit temporären Dateien messen. Der Pipeline-Ansatz ist bei großen Datenmengen überlegen, weil:
- Die Stufen nebenläufig laufen — CPU und I/O überlappen sich.
- Für Zwischendaten ist kein Festplatten-I/O erforderlich — nur die endgültige Ausgabe wird auf die Festplatte geschrieben.
- Der Speicherbedarf bleibt unabhängig von der Eingabegröße konstant (Stream statt Puffer).
Ein einfacher Benchmark zum Vergleich beider Ansätze:
#!/usr/bin/env bash
# Approach 1: Temp file (sequential)
time bash -c '
seq 1 5000000 > /tmp/nums.txt
sort -n /tmp/nums.txt > /tmp/sorted.txt
uniq /tmp/sorted.txt | wc -l
rm /tmp/nums.txt /tmp/sorted.txt
'
echo '---'
# Approach 2: Streaming pipeline (concurrent)
time bash -c 'seq 1 5000000 | sort -n | uniq | wc -l'Wissenscheck: Blockierungsverhalten von Named Pipes
Betrachten Sie das folgende Skript:
mkfifo /tmp/mypipe
echo 'hello' > /tmp/mypipe
echo 'done'Was geschieht, wenn dieses Skript ohne Hintergrundprozesse oder Leser ausgeführt wird?
Rückblick: Streaming-Pipelines und Named Pipes
In dieser Lektion haben Sie untersucht, wie sich Daten effizient zwischen Prozessen verschieben lassen, ohne temporäre Dateien zu verwenden:
- Anonyme Pipes (
|) verbinden direkt aufeinanderfolgende Befehle und führen alle Stufen gleichzeitig mit automatischer Rückstaukontrolle aus. - Named Pipes (
mkfifo) erstellen einen FIFO-Dateisystemeintrag, über den unabhängige oder im Hintergrund laufende Prozesse Daten als Stream austauschen können — Schreibvorgänge werden blockiert, bis ein Leser vorhanden ist. - Prozesssubstitution (
<(cmd),>(cmd)) ermöglicht es Befehlen, die Dateinamen erwarten, Streams transparent zu lesen oder zu erzeugen. tee+>()verteilt einen Stream auf mehrere gleichzeitig laufende Verbraucher, ohne die Quelle erneut zu lesen.- Fan-in führt mehrere Produzenten über eine gemeinsame FIFO zu einem Verbraucher zusammen.
- Rückstaukontrolle und Blockieren sind Funktionen und keine Fehler — führen Sie jedoch immer mindestens eine Seite eines FIFO-Paars im Hintergrund aus, um einen Deadlock zu vermeiden.
- Verwenden Sie
pvodermbuffer, um größere Puffer hinzuzufügen und den Durchsatz zu überwachen, wenn die einzelnen Stufen stoßweise arbeiten.
Diese Techniken bilden die Grundlage für die leistungsstarke Bash-Datenverarbeitung: Verarbeiten Sie Daten im GB-Maßstab mit konstantem Speicherbedarf und maximaler Parallelität von CPU- und I/O-Vorgängen.
Lerne Bash mit einem KI-Tutor — kostenlos
Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.
- Kurse
- 22
- Lektionen
- 88
Häufig gestellte Fragen
Ist die Lektion „Streaming-Pipelines und Named Pipes für hohen Durchsatz“ kostenlos?
Ja — der vollständige Text von „Streaming-Pipelines und Named Pipes für hohen Durchsatz“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Linux Command Line & Bash Scripting Mastery-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Linux Command Line & Bash Scripting Mastery-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „Streaming-Pipelines und Named Pipes für hohen Durchsatz“?
Verwenden Sie FIFOs und Prozesssubstitution, um Daten ohne Zwischendateien zwischen Verarbeitungsschritten zu streamen. Du übst Linux Command Line & Bash Scripting Mastery mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um Linux Command Line & Bash Scripting Mastery zu starten?
Keine Vorkenntnisse erforderlich. Linux Command Line & Bash Scripting Mastery auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 4 von 4.
Wie lange dauert die Lektion „Streaming-Pipelines und Named Pipes für hohen Durchsatz“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser Linux Command Line & Bash Scripting Mastery-Lektion Code schreiben und ausführen?
Ja. Jede Linux Command Line & Bash Scripting Mastery-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- Skripte profilieren und unnötige Subshells vermeiden
- Parallelisierung mit xargs -P und Hintergrundjobs
- Workloads mit GNU parallel orchestrieren
- Streaming-Pipelines und Named Pipes für hohen Durchsatz