0Pricing
Linux Command Line & Bash Scripting Mastery · Lekcja

Równoległość z xargs -P i zadaniami w tle

Uruchamiaj niezależne zadania współbieżnie, korzystając z trybu równoległego xargs i zarządzanych pul zadań działających w tle.

Równoległość z xargs -P i zadaniami w tle to bezpłatna lekcja Linux Command Line & Bash Scripting Mastery na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Linux Command Line & Bash Scripting Mastery, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Dlaczego wykonywanie sekwencyjne jest powolne

Gdy uruchamiasz polecenia jedno po drugim w skrypcie powłoki, pozostawiasz rdzenie procesora bezczynne. Rozważ zmianę rozmiaru 500 obrazów: każde wywołanie convert używa jednego rdzenia, podczas gdy pozostałe siedem pozostaje bezczynne.

Wykonywanie równoległe rozwiązuje ten problem, przekazując wiele zadań do realizacji jednocześnie. W Bash ułatwiają to dwa podstawowe narzędzia:

  • xargs -P — rozdziela listę danych wejściowych między N równoległych procesów roboczych
  • Zadania w tle (&) + wait — ręcznie uruchamia procesy i zbiera ich wyniki

Ta lekcja obejmuje oba podejścia, aby można było wybrać właściwe narzędzie do danej sytuacji.

Powtórzenie podstaw xargs

Zanim dodasz wykonywanie równoległe, przypomnij sobie, jak działa xargs. Odczytuje elementy ze standardowego wejścia i przekazuje je jako argumenty do polecenia.

Flaga -I {} pozwala umieścić element wejściowy w dowolnym miejscu ciągu polecenia, a nie tylko na jego końcu.

Poniższy przykład konwertuje każdy plik .txt na wielkie litery za pomocą tr. Każdy plik jest przetwarzany pojedynczo (sekwencyjny punkt odniesienia).

#!/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

Wprowadzenie do xargs -P

Dodaj do xargs flagę -P N, aby uruchamiać N procesów równolegle. xargs automatycznie zarządza pulą procesów roboczych — gdy zwolni się jedno miejsce, następny element jest uruchamiany natychmiast.

  • -P 0 — uruchamia tyle procesów, ile jest danych wejściowych (należy zachować ostrożność przy dużych listach)
  • -P 4 — utrzymuje najwyżej 4 procesy robocze działające w dowolnym momencie
  • -n 1 — przekazuje dokładnie jeden element wejściowy do każdego uruchomionego procesu (często używana flaga uzupełniająca)

Połączenie -n 1 -P 4 to najczęściej stosowany wzorzec: jeden element na proces roboczy, cztery procesy jednocześnie.

#!/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 "$@"' _

Równoległe przetwarzanie plików

Praktyczny przypadek użycia: jednoczesne kompresowanie wielu plików dziennika. Bez -P każde wywołanie gzip blokuje następne. Z -P 8 jednocześnie działa do ośmiu operacji kompresji, wykorzystując wszystkie rdzenie procesora.

Zwróć uwagę, że -n 1 gwarantuje przekazanie każdej równoległej instancji dokładnie jednej nazwy pliku — ma to kluczowe znaczenie, gdy nazwy mogą zawierać spacje (dla bezpieczeństwa połącz z -d '\n' albo z -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

Wybór właściwej wartości -P

Ustawienie zbyt niskiej wartości -P powoduje niewykorzystanie rdzeni, a zbyt wysokiej — nadmierne przełączanie procesów. Dobrym punktem wyjścia jest liczba logicznych rdzeni procesora:

  • Zadania obciążające procesor (kompresowanie, kodowanie): -P $(nproc)
  • Zadania zależne od operacji wejścia-wyjścia (wywołania sieciowe, odczyt z dysku): -P $(($(nproc) * 4)) lub więcej, ponieważ procesy robocze większość czasu spędzają na oczekiwaniu
  • Zadania ograniczone ilością pamięci: oblicz available_RAM / task_RAM_usage i ustaw na tej podstawie limit

nproc zwraca liczbę dostępnych jednostek przetwarzania, dzięki czemu stanowi przenośny zamiennik wartości wpisywanych na stałe.

#!/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

Zadania w tle za pomocą &

Czasami potrzebujesz większej kontroli, niż zapewnia xargs — na przykład obsługi błędów dla poszczególnych zadań, dynamicznych list lub złożonych zestawów argumentów. Użyj wbudowanego w powłokę operatora uruchamiania w tle &, aby ręcznie uruchamiać zadania.

Dodanie & do dowolnego polecenia natychmiast przekazuje sterowanie z powrotem do skryptu. Proces potomny działa w tle, podczas gdy proces nadrzędny wykonuje dalsze instrukcje. Na końcu wywołaj wait, aby wstrzymać działanie do czasu zakończenia wszystkich procesów potomnych.

#!/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."

Ograniczanie współbieżności za pomocą puli zadań

Jednoczesne uruchomienie wszystkich zadań za pomocą & może wyczerpać pamięć, gdy lista jest duża. Pula zadań utrzymuje w danym momencie najwyżej N uruchomionych zadań:

  • Po uruchomieniu każdego zadania sprawdź, ile zadań w tle jest obecnie aktywnych, za pomocą jobs -r | wc -l
  • Jeśli liczba osiągnie limit, wywołaj wait -n (Bash 4.3+), aby zaczekać na zakończenie dowolnego jednego zadania przed uruchomieniem następnego

Ten wzorzec naśladuje wewnętrzne działanie xargs -P, ale zapewnia pełną elastyczność skryptu przy obsłudze każdego zadania.

#!/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."

Pobieranie kodów zakończenia zadań równoległych

W przypadku zadań w tle istotnym problemem jest to, że jeśli proces potomny zakończy się błędem, skrypt nadrzędny nie dowie się o tym automatycznie. Należy zapisać PID każdego procesu potomnego i sprawdzić jego status zakończenia za pomocą wait <pid>.

Poniższy wzorzec zapisuje każdy PID w tablicy, a następnie iteruje po tej tablicy, wywołując wait "$pid", które zwraca kod zakończenia konkretnego procesu potomnego.

#!/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; }

Równoległe pobieranie za pomocą xargs -P

Operacje wejścia-wyjścia w sieci są typowym przypadkiem zastosowania wysokiego stopnia równoległości — każdy proces roboczy większość czasu spędza na oczekiwaniu na dane. Poniższy przykład jednocześnie pobiera wiele adresów URL i zapisuje każdy z nich w pliku o unikatowej nazwie.

Użyte najważniejsze flagi:

  • -P 8 — osiem jednoczesnych procesów curl
  • -n 1 — jeden adres URL na wywołanie curl
  • --create-dirs -o — curl zapisuje dane w pliku o wyprowadzonej nazwie
#!/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

Łączenie find, xargs -P i funkcji powłoki

Aby użyć wielowierszowej funkcji powłoki z xargs, musisz ją wyeksportować za pomocą export -f function_name, a następnie wywołać w xargs za pomocą bash -c 'function_name "$@"' _.

Ten wzorzec zapewnia pełne możliwości skryptów w każdym równoległym procesie roboczym: rejestrowanie, obsługę błędów i logikę warunkową — osobno dla każdego elementu.

#!/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

Pomiar przyspieszenia za pomocą time

Zawsze wykonuj pomiary, zanim ogłosisz poprawę. Owiń równoległe polecenie w time i porównaj je z sekwencyjnym punktem odniesienia. Rzeczywiste przyspieszenie zależy od:

  • Niezależności zadań — zadania nie mogą współdzielić zapisywanego stanu bez blokad
  • Narzutu — koszt uruchomienia procesu (około 5–20 ms na proces) ma znaczenie w przypadku małych zadań
  • Konkurencji o zasoby — operacje wejścia-wyjścia na dysku mogą osiągnąć limit, zanim zrobi to procesor

Poniżej przedstawiono prosty wzorzec testu wydajności — uruchom go sekwencyjnie, a następnie równolegle i porównaj czasy rzeczywiste real.

#!/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' _

Sprawdzenie wiedzy: działanie xargs -P

Sprawdź swoją wiedzę na temat wykonywania równoległego za pomocą xargs -P.

Podsumowanie lekcji

Masz teraz do dyspozycji dwie niezawodne techniki wykonywania równoległego w Bash:

  • xargs -n 1 -P N — najprostsze podejście; xargs automatycznie zarządza pulą procesów roboczych. Najlepsze, gdy dane wejściowe są zwykłą listą, a każdy element odpowiada jednemu poleceniu.
  • Zadania w tle (&) + wait — pełna kontrola nad skryptem; rozwiązanie niezbędne, gdy potrzebujesz PID-ów poszczególnych zadań, dynamicznych danych wejściowych lub szczegółowej obsługi kodów zakończenia. Użyj wait -n wraz z licznikiem, aby ograniczyć współbieżność.

Najważniejsze zasady na przyszłość:

  • Eksportuj funkcje powłoki za pomocą export -f, zanim przekażesz je przez xargs
  • Używaj -print0 / -0, aby bezpiecznie obsługiwać nazwy plików zawierające spacje
  • Zapisuj PID-y w tablicy i wywołuj osobno wait "$pid", aby wykrywać błędy
  • Wykonuj testy wydajności za pomocą time — równoległość przynosi korzyści tylko wtedy, gdy narzut zadania przewyższa koszt uruchomienia procesu
  • Ustaw -P $(nproc) dla zadań obciążających procesor oraz większą wielokrotność dla zadań zależnych od operacji wejścia-wyjścia

Często zadawane pytania

Czy lekcja „Równoległość z xargs -P i zadaniami w tle” jest bezpłatna?

Tak — pełny tekst „Równoległość z xargs -P i zadaniami w tle” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Linux Command Line & Bash Scripting Mastery, przejdź na CoddyKit PRO. Kurs Linux Command Line & Bash Scripting Mastery zawiera 4 lekcji w sumie.

Co nauczysz się w „Równoległość z xargs -P i zadaniami w tle”?

Uruchamiaj niezależne zadania współbieżnie, korzystając z trybu równoległego xargs i zarządzanych pul zadań działających w tle. Ćwiczysz Linux Command Line & Bash Scripting Mastery z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.

Czy potrzebuję doświadczenia, aby zacząć Linux Command Line & Bash Scripting Mastery?

Nie wymagamy żadnego doświadczenia. Linux Command Line & Bash Scripting Mastery w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.

Ile czasu zajmuje lekcja „Równoległość z xargs -P i zadaniami w tle”?

Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.

Czy mogę pisać i uruchamiać kod w tej lekcji Linux Command Line & Bash Scripting Mastery?

Tak. Każda lekcja Linux Command Line & Bash Scripting Mastery zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.

Wszystkie lekcje w tym kursie

  1. Profilowanie skryptów i unikanie zbędnych podpowłok
  2. Równoległość z xargs -P i zadaniami w tle
  3. Orkiestracja obciążeń za pomocą GNU parallel
  4. Potoki strumieniowe i nazwane potoki zapewniające przepustowość
← Powrót do Linux Command Line & Bash Scripting Mastery