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_demoWprowadzenie 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_demoWybó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_usagei 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 -sSOZadania 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_demoPomiar 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 -nwraz 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 przezxargs - 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
- Profilowanie skryptów i unikanie zbędnych podpowłok
- Równoległość z xargs -P i zadaniami w tle
- Orkiestracja obciążeń za pomocą GNU parallel
- Potoki strumieniowe i nazwane potoki zapewniające przepustowość