0Pricing
Linux Command Line & Bash Scripting Mastery · Lektion

Parallelisierung mit xargs -P und Hintergrundjobs

Führen Sie unabhängige Aufgaben mithilfe des parallelen Modus von xargs und verwalteter Hintergrundjob-Pools gleichzeitig aus.

Parallelisierung mit xargs -P und Hintergrundjobs ist eine kostenlose Linux Command Line & Bash Scripting Mastery-Lektion auf CoddyKit. Dies ist Lektion 2 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 sequenzielle Ausführung langsam ist

Wenn Sie Befehle in einem Shell-Skript nacheinander ausführen, bleiben CPU-Kerne ungenutzt. Stellen Sie sich vor, Sie ändern die Größe von 500 Bildern: Jeder Aufruf von convert verwendet einen Kern, während die anderen sieben ungenutzt bleiben.

Parallelisierung behebt dieses Problem, indem mehrere Aufgaben gleichzeitig gestartet werden. Zwei wichtige Werkzeuge in Bash machen das einfach:

  • xargs -P – verteilt eine Liste von Eingaben auf N parallel arbeitende Worker-Prozesse
  • Hintergrundjobs (&) + wait – startet Prozesse manuell und wartet ihre Ergebnisse ab

Diese Lektion behandelt beide Ansätze, damit Sie für jede Situation das passende Werkzeug auswählen können.

Auffrischung der xargs-Grundlagen

Bevor Sie Parallelisierung hinzufügen, rufen wir uns die Funktionsweise von xargs ins Gedächtnis. Es liest Elemente von stdin und übergibt sie als Argumente an einen Befehl.

Mit dem Schalter -I {} können Sie das Eingabeelement an beliebiger Stelle in der Befehlszeichenfolge einsetzen, nicht nur am Ende.

Das folgende Beispiel wandelt jede .txt-Datei mithilfe von tr in Großbuchstaben um. Jede Datei wird einzeln verarbeitet (sequenzielle Ausgangsbasis).

#!/usr/bin/env bash
# Create sample files
mkdir -p /tmp/xargs_demo
for i in 1 2 3; do
  echo "hello world $i" > /tmp/xargs_demo/file$i.txt
done

# Process files one at a time (sequential)
find /tmp/xargs_demo -name '*.txt' | xargs -I {} sh -c 'tr a-z A-Z < "$1"' _ {}

# Cleanup
rm -rf /tmp/xargs_demo

Einführung in xargs -P

Fügen Sie -P N zu xargs hinzu, um bis zu N Prozesse parallel auszuführen. xargs verwaltet den Worker-Pool automatisch – sobald ein Platz frei wird, startet sofort das nächste Element.

  • -P 0 – startet so viele Prozesse wie Eingaben vorhanden sind (bei großen Listen mit Vorsicht verwenden)
  • -P 4 – lässt höchstens 4 Worker gleichzeitig laufen
  • -n 1 – übergibt pro aufgerufenem Prozess genau ein Eingabeelement (ein häufig gemeinsam verwendeter Schalter)

Die Kombination -n 1 -P 4 ist das gängigste Muster: ein Element pro Worker, vier Worker gleichzeitig.

#!/usr/bin/env bash
# Simulate 8 tasks, each taking ~1 second
# Sequential would take ~8s; parallel with -P 4 takes ~2s

process_item() {
  local item="$1"
  sleep 1
  echo "Done: $item"
}
export -f process_item

time printf '%s\n' task{1..8} | xargs -n 1 -P 4 bash -c 'process_item "$@"' _

Parallele Dateiverarbeitung

Ein praktischer Anwendungsfall: Viele Protokolldateien gleichzeitig komprimieren. Ohne -P blockiert jeder Aufruf von gzip den nächsten. Mit -P 8 laufen bis zu acht Komprimierungen gleichzeitig und lasten alle CPU-Kerne aus.

Beachten Sie, dass -n 1 sicherstellt, dass jeder parallele Worker genau einen Dateinamen erhält – entscheidend, wenn Dateinamen Leerzeichen enthalten können (kombinieren Sie dies sicherheitshalber mit -d '\n' oder -print0 / -0).

#!/usr/bin/env bash
# Create dummy log files
mkdir -p /tmp/logs_demo
for i in $(seq 1 12); do
  dd if=/dev/urandom bs=1K count=64 2>/dev/null > /tmp/logs_demo/app_$i.log
done

echo "Files before: $(ls /tmp/logs_demo | wc -l)"

# Compress all .log files in parallel (up to 8 workers)
find /tmp/logs_demo -name '*.log' -print0 \
  | xargs -0 -n 1 -P 8 gzip --fast

echo "Files after : $(ls /tmp/logs_demo | wc -l)"
rm -rf /tmp/logs_demo

Den richtigen -P-Wert auswählen

Ein zu niedriger Wert für -P lässt CPU-Kerne ungenutzt, ein zu hoher Wert führt zu Thrashing. Ein guter Ausgangspunkt ist die Anzahl der logischen CPU-Kerne:

  • CPU-bound-Aufgaben (Komprimierung, Kodierung): -P $(nproc)
  • I/O-bound-Aufgaben (Netzwerkaufrufe, Festplattenzugriffe): -P $(($(nproc) * 4)) oder höher, da die Worker die meiste Zeit warten
  • Arbeitsspeicherbeschränkte Aufgaben: Berechnen Sie available_RAM / task_RAM_usage und begrenzen Sie den Wert entsprechend

nproc gibt die Anzahl der verfügbaren Verarbeitungseinheiten zurück und ist damit ein portabler Ersatz für fest codierte Zahlen.

#!/usr/bin/env bash
CORES=$(nproc)
IO_WORKERS=$(( CORES * 4 ))

echo "CPU cores   : $CORES"
echo "CPU-bound -P: $CORES"
echo "I/O-bound -P: $IO_WORKERS"

# Example: parallel curl downloads (I/O-bound)
# printf '%s\n' url1 url2 ... | xargs -n 1 -P "$IO_WORKERS" curl -sSO

Hintergrundjobs mit &

Manchmal benötigen Sie mehr Kontrolle, als xargs bietet – etwa eine Fehlerbehandlung pro Job, dynamische Listen oder komplexe Argumentstrukturen. Verwenden Sie den integrierten Hintergrundoperator & der Shell, um Jobs manuell zu starten.

Wenn Sie & an einen beliebigen Befehl anhängen, erhält das Skript sofort die Kontrolle zurück. Der Kindprozess läuft im Hintergrund, während der Elternprozess fortfährt. Rufen Sie am Ende wait auf, um zu warten, bis alle Kindprozesse beendet sind.

#!/usr/bin/env bash
process() {
  local id="$1"
  sleep $(( RANDOM % 3 + 1 ))
  echo "Job $id finished at $(date +%T)"
}

echo "Launching 5 background jobs..."
for id in $(seq 1 5); do
  process "$id" &
done

wait   # Block until every background job completes
echo "All jobs done."

Nebenläufigkeit mit einem Job-Pool begrenzen

Wenn Sie alle Jobs gleichzeitig mit & starten, kann bei einer großen Liste der Arbeitsspeicher erschöpft werden. Ein Job-Pool stellt sicher, dass jederzeit höchstens N Jobs ausgeführt werden:

  • Prüfen Sie nach dem Start jedes Jobs mit jobs -r | wc -l, wie viele Hintergrundjobs derzeit aktiv sind
  • Wenn der Zähler das Limit erreicht, rufen Sie wait -n (Bash 4.3+) auf, um auf die Beendigung eines beliebigen Jobs zu warten, bevor Sie den nächsten starten

Dieses Muster entspricht intern der Funktionsweise von xargs -P, bietet Ihnen aber vollständige Flexibilität beim Skripten rund um jeden einzelnen Job.

#!/usr/bin/env bash
MAX_JOBS=3

process() {
  local id="$1"
  sleep $(( RANDOM % 3 + 1 ))
  echo "Task $id done"
}

for id in $(seq 1 10); do
  # Throttle: wait for a slot if pool is full
  while (( $(jobs -r | wc -l) >= MAX_JOBS )); do
    wait -n 2>/dev/null || true
  done
  process "$id" &
done

wait
echo "All 10 tasks complete."

Exit-Codes paralleler Jobs erfassen

Ein wichtiger Aspekt bei Hintergrundjobs: Wenn ein Kindprozess fehlschlägt, erfährt der Elternprozess davon nicht automatisch. Sie müssen die PID jedes Kindprozesses erfassen und seinen Exit-Status mit wait <pid> überprüfen.

Das folgende Muster speichert jede PID in einem Array und durchläuft anschließend das Array. Dabei wird wait "$pid" aufgerufen, das den Exit-Code des jeweiligen Kindprozesses zurückgibt.

#!/usr/bin/env bash
set -euo pipefail

task() {
  local id="$1"
  sleep 1
  if (( id == 3 )); then
    echo "Task $id: FAILED" >&2
    return 1
  fi
  echo "Task $id: ok"
}

pids=()
for id in $(seq 1 5); do
  task "$id" &
  pids+=("$!")
done

failed=0
for pid in "${pids[@]}"; do
  if ! wait "$pid"; then
    echo "PID $pid exited with error" >&2
    (( failed++ ))
  fi
done

(( failed == 0 )) && echo "All OK" || { echo "$failed job(s) failed"; exit 1; }

Parallele Downloads mit xargs -P

Netzwerk-I/O ist ein typischer Anwendungsfall für eine hohe Parallelität – jeder Worker wartet die meiste Zeit auf Bytes. Das folgende Beispiel ruft mehrere URLs gleichzeitig ab und speichert jede davon in einer Datei mit eindeutigem Namen.

Verwendete wichtige Schalter:

  • -P 8 – acht gleichzeitig ausgeführte curl-Prozesse
  • -n 1 – eine URL pro curl-Aufruf
  • --create-dirs -o – curl speichert die Datei unter einem abgeleiteten Dateinamen
#!/usr/bin/env bash
# Download several small public files in parallel
URLs=(
  "https://httpbin.org/bytes/1024"
  "https://httpbin.org/bytes/2048"
  "https://httpbin.org/bytes/512"
  "https://httpbin.org/bytes/4096"
)

mkdir -p /tmp/parallel_dl

printf '%s\n' "${URLs[@]}" | xargs -n 1 -P 4 bash -c '
  url="$1"
  out="/tmp/parallel_dl/$(echo "$url" | md5sum | cut -c1-8).bin"
  curl -sSf "$url" -o "$out" && echo "Saved $out"
' _

ls -lh /tmp/parallel_dl/
rm -rf /tmp/parallel_dl

find, xargs -P und Shell-Funktionen kombinieren

Um eine mehrzeilige Shell-Funktion mit xargs zu verwenden, müssen Sie sie mit export -f function_name exportieren und anschließend innerhalb von xargs über bash -c 'function_name "$@"' _ aufrufen.

Dieses Muster ermöglicht die vollständige Leistungsfähigkeit von Skripten innerhalb jedes parallelen Workers: Protokollierung, Fehlerbehandlung und bedingte Logik – jeweils pro Element.

#!/usr/bin/env bash
mkdir -p /tmp/proc_demo
for i in $(seq 1 8); do echo "data $i" > /tmp/proc_demo/item_$i.txt; done

process_file() {
  local f="$1"
  local base
  base=$(basename "$f" .txt)
  # Simulate work: count words and append a timestamp
  local wc
  wc=$(wc -w < "$f")
  echo "[$base] words=$wc processed=$(date +%T)" >> "/tmp/proc_demo/${base}.result"
}
export -f process_file

find /tmp/proc_demo -name '*.txt' -print0 \
  | xargs -0 -n 1 -P "$(nproc)" bash -c 'process_file "$@"' _

grep '' /tmp/proc_demo/*.result
rm -rf /tmp/proc_demo

Geschwindigkeitssteigerung mit time messen

Messen Sie immer, bevor Sie eine Verbesserung behaupten. Umschließen Sie Ihren parallelen Befehl mit time und vergleichen Sie ihn mit der sequenziellen Ausgangsbasis. Die tatsächliche Beschleunigung hängt von Folgendem ab:

  • Unabhängigkeit der Aufgaben – Aufgaben dürfen ohne Sperren keinen gemeinsam beschreibbaren Zustand verwenden
  • Overhead – die Kosten für das Starten eines Prozesses (etwa 5–20 ms pro Prozess) sind bei sehr kleinen Aufgaben relevant
  • Ressourcenkonkurrenz – die Festplatten-I/O kann gesättigt sein, noch bevor die CPU ausgelastet ist

Das folgende einfache Benchmark-Muster zeigt den Ablauf: Führen Sie den Befehl zunächst sequenziell und anschließend parallel aus und vergleichen Sie die real-Zeiten.

#!/usr/bin/env bash
work() { sleep 0.2; }   # simulate a 200ms task
export -f work

ITEMS=$(seq 1 16)

echo "=== Sequential ==="
time printf '%s\n' $ITEMS | xargs -n 1 bash -c 'work' _

echo
echo "=== Parallel ($(nproc) workers) ==="
time printf '%s\n' $ITEMS | xargs -n 1 -P "$(nproc)" bash -c 'work' _

Wissenscheck: Verhalten von xargs -P

Testen Sie Ihr Verständnis der parallelen Ausführung mit xargs -P.

Lektionszusammenfassung

Sie verfügen nun über zwei zuverlässige Techniken für die parallele Ausführung in Bash:

  • xargs -n 1 -P N – der einfachste Ansatz; xargs verwaltet den Worker-Pool automatisch. Optimal, wenn Ihre Eingabe aus einer einfachen Liste besteht und jedes Element einem Befehl zugeordnet wird.
  • Hintergrundjobs (&) + wait – vollständige Kontrolle beim Skripten; unverzichtbar, wenn Sie PIDs pro Job, dynamische Eingaben oder eine detaillierte Behandlung von Exit-Codes benötigen. Verwenden Sie wait -n zusammen mit einem Zähler, um die Nebenläufigkeit zu begrenzen.

Wichtige Regeln für die Zukunft:

  • Exportieren Sie Shell-Funktionen mit export -f, bevor Sie sie an xargs übergeben
  • Verwenden Sie -print0 / -0, um Dateinamen mit Leerzeichen sicher zu verarbeiten
  • Speichern Sie PIDs in einem Array und rufen Sie wait "$pid" für jede PID einzeln auf, um Fehler zu erkennen
  • Führen Sie Benchmarks mit time durch – Parallelisierung bringt nur dann einen Vorteil, wenn der Aufgaben-Overhead die Kosten für das Starten von Prozessen übersteigt
  • Setzen Sie für CPU-bound-Workloads -P $(nproc) und für I/O-bound-Workloads ein höheres Vielfaches

Häufig gestellte Fragen

Ist die Lektion „Parallelisierung mit xargs -P und Hintergrundjobs“ kostenlos?

Ja — der vollständige Text von „Parallelisierung mit xargs -P und Hintergrundjobs“ 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 „Parallelisierung mit xargs -P und Hintergrundjobs“?

Führen Sie unabhängige Aufgaben mithilfe des parallelen Modus von xargs und verwalteter Hintergrundjob-Pools gleichzeitig aus. 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 2 von 4.

Wie lange dauert die Lektion „Parallelisierung mit xargs -P und Hintergrundjobs“?

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

  1. Skripte profilieren und unnötige Subshells vermeiden
  2. Parallelisierung mit xargs -P und Hintergrundjobs
  3. Workloads mit GNU parallel orchestrieren
  4. Streaming-Pipelines und Named Pipes für hohen Durchsatz
← Zurück zu Linux Command Line & Bash Scripting Mastery