Orkiestracja obciążeń za pomocą GNU parallel
Rozdzielaj duże zbiory danych wejściowych między rdzenie za pomocą GNU parallel, gniazd zadań i porządkowania wyników.
Orkiestracja obciążeń za pomocą GNU parallel to bezpłatna lekcja Linux Command Line & Bash Scripting Mastery na CoddyKit. To lekcja 3 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.
Czym jest GNU parallel i dlaczego warto go używać
GNU parallel to narzędzie powłoki umożliwiające równoległe uruchamianie zadań na jednym komputerze lub na wielu komputerach. Zamiast przetwarzać dużą listę elementów pojedynczo w pętli for, parallel rozdziela pracę między wszystkie dostępne rdzenie procesora i wykorzystuje je jednocześnie.
- Szybkość: zadanie trwające sekwencyjnie 8 minut może zakończyć się w około 1 minutę na komputerze z 8 rdzeniami.
- Prostota: narzędzie przyjmuje dane ze standardowego wejścia, plików lub list argumentów — bez ręcznego zarządzania procesami.
- Bezpieczeństwo: dane wyjściowe z różnych zadań są rozdzielone; wyniki nigdy nie przeplatają się ze sobą.
Zainstaluj je za pomocą sudo apt install parallel (Debian/Ubuntu) lub brew install parallel (macOS). Wersję sprawdzisz poleceniem parallel --version.
Pierwsze polecenie parallel
Najprostsza forma parallel odczytuje elementy ze standardowego wejścia i uruchamia polecenie dla każdego z nich. Symbol zastępczy {} oznacza bieżący element wejściowy.
Poniższy przykład jednocześnie kompresuje pięć plików dziennika za pomocą gzip. Bez parallel każdy plik byłby kompresowany po kolei. Z jego użyciem jednocześnie można kompresować do N plików, gdzie N oznacza liczbę rdzeni procesora.
#!/usr/bin/env bash
# Create sample files first
for i in 1 2 3 4 5; do
dd if=/dev/urandom bs=1M count=2 of="log_${i}.txt" 2>/dev/null
done
# Compress all of them in parallel
ls log_*.txt | parallel gzip {}
echo "Done. Compressed files:"
ls log_*.txt.gzSterowanie slotami zadań za pomocą -j
Domyślnie parallel uruchamia jedno zadanie na każdy rdzeń procesora. Możesz zmienić to ustawienie za pomocą flagi -j (lub --jobs).
-j 4— uruchamia dokładnie 4 zadania jednocześnie-j 0— uruchamia tyle zadań, ile jest danych wejściowych (używaj ostrożnie!)-j 200%— uruchamia dwa razy więcej zadań niż jest rdzeni procesora (przydatne w przypadku zadań zależnych od operacji wejścia-wyjścia)-j 50%— wykorzystuje tylko połowę dostępnych rdzeni
W przypadku zadań obciążających procesor często optymalną wartością jest -j $(nproc). W przypadku zadań związanych z operacjami sieciowymi lub dyskowymi można bezpiecznie przekroczyć liczbę rdzeni, ponieważ procesy większość czasu spędzają na oczekiwaniu.
#!/usr/bin/env bash
# Show how many cores are available
echo "CPU cores: $(nproc)"
# Run 8 sleep jobs but limit to 3 at a time
# -j 3 means at most 3 jobs run simultaneously
seq 1 8 | parallel -j 3 'echo "Starting job {}"; sleep 1; echo "Done job {}"'
echo "All jobs finished."Odczytywanie danych wejściowych z plików i argumentów
parallel zapewnia elastyczność w wyborze źródła listy danych wejściowych. Nie musisz ograniczać się do przekazywania danych ze standardowego wejścia przez potok.
- Z pliku:
parallel -a urls.txt wget {} - Lista argumentów w wierszu poleceń:
parallel echo ::: apple banana cherry - Wiele źródeł argumentów (iloczyn kartezjański):
parallel echo {1}-{2} ::: a b c ::: 1 2— tworzy a-1, a-2, b-1, b-2, c-1, c-2 - Jawnie ze standardowego wejścia:
cat list.txt | parallel -j4 process {}
Separator ::: informuje parallel, że następujące wartości mają być użyte jako źródło argumentów, a nie odczytywane ze standardowego wejścia.
#!/usr/bin/env bash
# Inline list with :::
parallel echo 'Hello from {}' ::: Alice Bob Carol Dave
echo '---'
# Cartesian product: combine two lists
# Generates: dev-v1, dev-v2, prod-v1, prod-v2
parallel echo 'Deploy {1} to env {2}' ::: v1 v2 ::: dev prodSymbole zastępcze: manipulowanie tokenami wejściowymi
parallel udostępnia kilka podstawień symboli zastępczych, które pozwalają automatycznie wyodrębniać części ciągu wejściowego — jest to szczególnie przydatne w przypadku ścieżek plików.
{}— cały element wejściowy{.}— element wejściowy bez rozszerzenia pliku (report.csv → report){/}— tylko nazwa bazowa (usuwa ścieżkę katalogu){//}— tylko ścieżka katalogu{/.}— nazwa bazowa bez rozszerzenia
Dzięki temu nie trzeba wywoływać basename / dirname wewnątrz polecenia zadania, co upraszcza i przyspiesza potoki.
#!/usr/bin/env bash
# Demonstrate placeholder substitutions
parallel --dry-run 'convert {} -resize 800x600 {.}_thumb.jpg' \
::: /photos/vacation/beach.png /photos/work/team.png
# {.} strips extension: /photos/vacation/beach
# Result command shown (--dry-run does NOT execute):
# convert /photos/vacation/beach.png -resize 800x600 /photos/vacation/beach_thumb.jpg
# convert /photos/work/team.png -resize 800x600 /photos/work/team_thumb.jpg
echo 'No files were changed (dry run)'Zachowywanie kolejności danych wyjściowych za pomocą --keep-order
Gdy zadania kończą się w różnym czasie, ich dane wyjściowe stdout pojawiają się w kolejności, w której zadania się kończą. Może to utrudniać odczytywanie dzienników i powodować problemy z analizą danych przez kolejne etapy.
Kolejność danych wyjściowych kontrolują dwie flagi:
--keep-order(-k) — wyświetla dane wyjściowe każdego zadania w tej samej kolejności co dane wejściowe, nawet jeśli późniejsze zadanie zakończy się wcześniej. Dane wyjściowe są buforowane do czasu zakończenia wcześniejszych zadań.--line-buffer— rozwiązanie pośrednie: wyświetla kompletne wiersze w miarę ich pojawiania się, bez oczekiwania na zakończenie zadania, ale nigdy nie przeplata częściowo zapisanych wierszy.
Użyj -k, gdy odbiorca kolejnego etapu oczekuje wyników w kolejności danych wejściowych (np. podczas tworzenia posortowanego raportu). Pomiń tę flagę, gdy kolejność nie ma znaczenia i chcesz zobaczyć wyniki jak najszybciej.
#!/usr/bin/env bash
# Without -k: output order is unpredictable
echo '--- Without --keep-order ---'
seq 5 1 1 | parallel 'sleep 0.$((RANDOM % 5)); echo "Result for {}"'
echo
# With -k: output always appears as 5, 4, 3, 2, 1
echo '--- With --keep-order (-k) ---'
seq 5 1 1 | parallel -k 'sleep 0.$((RANDOM % 5)); echo "Result for {}"'Grupowanie danych wyjściowych w celu uniknięcia przeplatania
Nawet przy uporządkowanych danych wyjściowych, jeśli zadanie wypisuje wiele wierszy, wiersze te mogą przeplatać się z wierszami innego zadania uruchomionego w tym samym czasie. parallel rozwiązuje ten problem automatycznie, buforując kompletny stdout i stderr każdego zadania, a następnie wypisując je jako jeden niepodzielny blok po zakończeniu zadania.
To zachowanie jest domyślnie włączone. Można je wyłączyć za pomocą --ungroup, jeśli potrzebują Państwo strumieniowania danych wyjściowych na żywo (np. w przypadku długo działających zadań z paskami postępu), ale wtedy ponownie możliwe jest przeplatanie danych.
- Domyślnie: dane wyjściowe są grupowane według zadań — bezpieczne do przetwarzania.
--ungroup: dane wyjściowe są przesyłane na żywo — dobre rozwiązanie do interaktywnego monitorowania.--line-buffer: kompromis — wiersze nigdy nie są dzielone, ale zadania mogą przeplatać się na granicach wierszy.
Przekazywanie argumentów wewnątrz funkcji powłoki
Czasami praca, którą chcą Państwo zrównoleglić, obejmuje więcej niż jedno polecenie — jest wieloetapową funkcją powłoki. Funkcję można przekazać do parallel, używając export -f w połączeniu z env_parallel albo wywołując bezpośrednio bash -c.
Najbezpieczniejszym przenośnym podejściem w przypadku złożonych zadań jest wzorzec bash -c '...'. Symbol zastępczy {} jest przekazywany jako $1, gdy polecenie kończy się ciągiem _ {}.
#!/usr/bin/env bash
# Define a multi-step processing function
process_item() {
local item="$1"
echo "[START] $item"
# Simulate two steps
sleep 0.2
local result=$(echo "$item" | tr '[:lower:]' '[:upper:]')
echo "[END] $item -> $result"
}
export -f process_item
# Run the function in parallel for each input
echo 'alpha beta gamma delta epsilon' | tr ' ' '\n' \
| parallel -j 3 process_item {}Ograniczanie tempa i ponawianie prób za pomocą --delay i --retries
Podczas równoległego korzystania z usług zewnętrznych (API, serwerów zdalnych, baz danych) często potrzebują Państwo ograniczania częstotliwości żądań i odporności na błędy.
--delay N— odczekuje N sekund między uruchomieniem kolejnych zadań (dozwolone są wartości ułamkowe, takie jak0.5). Zapobiega przeciążeniu usługi.--retries N— jeśli zadanie zakończy się kodem różnym od zera, ponawia je maksymalnie N razy przed rezygnacją. Każda próba ponownego wykonania zajmuje nowe miejsce na zadanie.--timeout N— kończy zadanie, jeśli działa ono dłużej niż N sekund. W połączeniu z--retriespozwala sprawnie obsługiwać zawieszone zadania.
Przykład: pobieranie 50 adresów URL przy najwyżej 4 jednoczesnych połączeniach, z opóźnieniem 0,5 s między uruchomieniami oraz 3 ponowieniami w razie niepowodzenia.
#!/usr/bin/env bash
# Simulate downloading URLs with throttling and retries
# (using echo instead of curl so this is self-contained)
download_url() {
local url="$1"
# Randomly fail ~30% of the time to demo --retries
if (( RANDOM % 10 < 3 )); then
echo "FAIL: $url" >&2
return 1
fi
echo "OK: $url downloaded"
}
export -f download_url
printf 'https://example.com/file%d\n' $(seq 1 10) \
| parallel -j 4 --delay 0.2 --retries 3 download_url {}
echo 'All downloads attempted.'Rozdzielanie pracy między zdalne hosty za pomocą --sshloginfile
parallel może w przejrzysty sposób rozdzielać zadania między zdalne maszyny przez SSH, pełniąc funkcję lekkiego narzędzia do obliczeń klastrowych bez potrzeby instalowania specjalistycznego oprogramowania klastrowego.
--sshlogin user@host— uruchamia zadania na określonym zdalnym hoście.--sshloginfile machines.txt— odczytuje listę hostów z pliku (po jednym w wierszu). Użycie:jako specjalnego wpisu pozwala dodatkowo korzystać z maszyny lokalnej.--transfer— kopiuje plik wejściowy na zdalny host przed przetwarzaniem.--return {}— kopiuje plik wynikowy z powrotem po zakończeniu zadania.--cleanup— usuwa przesłane pliki ze zdalnego hosta po ich pobraniu.
Na zdalnym hoście musi być zainstalowany program parallel oraz skonfigurowane uwierzytelnianie SSH za pomocą kluczy (bez monitów o hasło).
Raportowanie postępu i rejestrowanie
W przypadku długo działających obciążeń kluczowe znaczenie ma monitorowanie postępu i diagnozowanie błędów po zakończeniu pracy.
--progress— wyświetla na żywo wiersz podsumowania pokazujący liczbę uruchomionych, ukończonych i pozostałych zadań.--eta— szacuje czas do zakończenia na podstawie dotychczasowego średniego czasu trwania zadań.--joblog results.log— zapisuje rozdzielany tabulatorami plik dziennika z jednym wierszem na każde ukończone zadanie, zawierającym kod wyjścia, czas działania i uruchomione polecenie. Jest nieoceniony podczas audytowania błędów.--resume --joblog results.log— pomija zadania, które już występują w pliku dziennika (z kodem wyjścia 0). Jeśli wykonanie partii zostanie przerwane, można je wznowić bez ponownego wykonywania pomyślnie zakończonych zadań.
Połączenie --joblog + --resume jest jedną z najpotężniejszych funkcji GNU parallel, umożliwiających tworzenie niezawodnych potoków produkcyjnych.
#!/usr/bin/env bash
LOGFILE="/tmp/parallel_demo_$$.log"
# Run jobs and record results to a log
seq 1 12 | parallel \
--jobs 4 \
--progress \
--joblog "$LOGFILE" \
'sleep 0.1; echo "Processed item {}"'
echo
echo '=== Job Log (first 5 entries) ==='
head -6 "$LOGFILE"
# Show only failed jobs (exit value != 0)
echo '=== Failed jobs ==='
awk 'NR>1 && $7 != 0 { print $0 }' "$LOGFILE" || echo '(none)'
rm -f "$LOGFILE"Sprawdzenie wiedzy: opcje miejsc na zadania
Sprawdźcie Państwo, jak parallel steruje współbieżnością.
Podsumowanie lekcji: orkiestracja obciążeń za pomocą GNU parallel
Omówili Państwo podstawowy zestaw narzędzi do rozdzielania dużych zbiorów danych wejściowych między rdzenie procesora za pomocą GNU parallel. Oto najważniejsze informacje:
- Podstawowe użycie: przekierujcie listę do
parallel command {}—{}jest zastępowane każdym elementem wejściowym. - Miejsca na zadania (
-j): precyzyjnie sterują współbieżnością — w przypadku pracy obciążającej procesor należy użyć liczby rdzeni, a w przypadku pracy obciążającej operacje wejścia-wyjścia — wyższych wartości procentowych. - Symbole zastępcze (
{.},{/},{//},{/.}) pozwalają wygodnie wyodrębniać składowe ścieżek bez dodatkowych poleceń. - Kontrola danych wyjściowych:
-kzachowuje kolejność danych wejściowych; domyślne grupowanie zapobiega przeplataniu wierszy;--ungroupzapewnia strumieniowanie na żywo. - Odporność:
--retries,--timeouti--delayzwiększają odporność potoków równoległych na niestabilne zadania i ograniczenia częstotliwości. - Możliwość audytu:
--joblogrejestruje wynik każdego zadania;--resumepozwala wznowić pracę od miejsca przerwania. - Skalowanie horyzontalne:
--sshloginfilerozdziela zadania między zdalne maszyny przez SSH bez narzutu typowego dla klastrów.
Opanowanie tych opcji zmienia parallel w gotowy do zastosowań produkcyjnych orkiestrator obciążeń, wbudowany bezpośrednio w powłokę.
Często zadawane pytania
Czy lekcja „Orkiestracja obciążeń za pomocą GNU parallel” jest bezpłatna?
Tak — pełny tekst „Orkiestracja obciążeń za pomocą GNU parallel” 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 „Orkiestracja obciążeń za pomocą GNU parallel”?
Rozdzielaj duże zbiory danych wejściowych między rdzenie za pomocą GNU parallel, gniazd zadań i porządkowania wyników. Ć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 3 z 4.
Ile czasu zajmuje lekcja „Orkiestracja obciążeń za pomocą GNU parallel”?
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ść