Оркестрация рабочих нагрузок с GNU parallel
Распределяйте большие наборы входных данных по ядрам с помощью GNU parallel, слотов заданий и упорядочивания результатов
«Оркестрация рабочих нагрузок с GNU parallel» — бесплатный урок Linux Command Line & Bash Scripting Mastery на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Linux Command Line & Bash Scripting Mastery, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Linux Command Line & Bash Scripting Mastery содержит 4 уроков всего.
Что такое GNU parallel и зачем он нужен
GNU parallel — это инструмент оболочки, позволяющий выполнять задания параллельно на одной или нескольких машинах. Вместо обработки большого списка элементов по одному в цикле for команда parallel одновременно распределяет эту работу по всем доступным ядрам CPU.
- Скорость: задача, выполняемая последовательно 8 минут, может завершиться примерно за 1 минуту на машине с 8 ядрами.
- Простота: инструмент принимает данные из стандартного ввода, файлов или списков аргументов — ручное управление процессами не требуется.
- Безопасность: вывод разных заданий хранится раздельно; результаты никогда не перемешиваются.
Установите инструмент с помощью sudo apt install parallel (Debian/Ubuntu) или brew install parallel (macOS). Проверьте установку с помощью parallel --version.
Ваша первая команда parallel
В простейшей форме parallel считывает элементы из стандартного ввода и запускает для каждого из них команду. Заполнитель {} обозначает текущий входной элемент.
В приведённом ниже примере пять файлов журналов одновременно сжимаются с помощью gzip. Без parallel файлы сжимались бы один за другим. С ним одновременно сжимается до N файлов, где N — количество ядер CPU.
#!/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.gzУправление слотами заданий с помощью -j
По умолчанию parallel запускает по одному заданию на каждое ядро CPU. Переопределить это поведение можно с помощью флага -j (или --jobs).
-j 4— одновременно выполнять ровно 4 задания-j 0— запускать столько заданий, сколько имеется входных данных (используйте осторожно!)-j 200%— запускать вдвое больше заданий, чем имеется ядер CPU (полезно для задач, ограниченных вводом-выводом)-j 50%— использовать только половину доступных ядер
Для задач, ограниченных CPU, значение -j $(nproc) часто является оптимальным. Для задач, связанных с сетевым вводом-выводом или диском, можно безопасно превысить количество ядер, поскольку задания большую часть времени ожидают.
#!/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."Чтение входных данных из файлов и аргументов
parallel гибко работает с источником списка входных данных. Вам не обязательно передавать его через стандартный ввод.
- Из файла:
parallel -a urls.txt wget {} - Встроенный список аргументов:
parallel echo ::: apple banana cherry - Несколько источников аргументов (декартово произведение):
parallel echo {1}-{2} ::: a b c ::: 1 2— создаёт a-1, a-2, b-1, b-2, c-1, c-2 - Явно из стандартного ввода:
cat list.txt | parallel -j4 process {}
Разделитель ::: сообщает parallel, что следующие значения нужно использовать как источник аргументов, а не считывать данные из стандартного ввода.
#!/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 prodЗаполнители: обработка входных элементов
parallel предоставляет несколько вариантов подстановки заполнителей, позволяющих автоматически извлекать части входной строки. Это особенно полезно, когда входные данные являются путями к файлам.
{}— полный входной элемент{.}— входной элемент без расширения файла (report.csv → report){/}— только базовое имя (путь к каталогу удаляется){//}— только путь к каталогу{/.}— базовое имя без расширения
Благодаря этому вызовы basename / dirname внутри команды задания не нужны, а конвейеры становятся понятнее и быстрее.
#!/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)'Сохранение порядка вывода с помощью --keep-order
Когда задания завершаются в разное время, их вывод в stdout появляется в порядке завершения. Из-за этого журналы становится трудно читать, а последующий разбор — ненадёжным.
Порядок вывода управляется двумя флагами:
--keep-order(-k) — выводит результат каждого задания в том же порядке, что и входные данные, даже если более позднее задание завершилось первым. Вывод буферизуется до завершения предыдущих заданий.--line-buffer— промежуточный вариант: выводит полностью сформированные строки по мере их поступления, не дожидаясь завершения задания, но никогда не перемешивает частично записанные строки.
Используйте -k, когда получателю вывода нужен тот же порядок, что и у входных данных (например, при создании отсортированного отчёта). Не используйте его, если порядок не важен и Вы хотите видеть результаты как можно скорее.
#!/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 {}"'Группировка вывода для предотвращения перемешивания
Даже при упорядоченном выводе строки одной задачи могут перемешиваться со строками другой задачи, выполняющейся одновременно. parallel автоматически решает эту проблему: буферизует полный стандартный вывод и стандартный вывод ошибок каждой задачи, а затем выводит их единым неделимым блоком после завершения задачи.
Это поведение включено по умолчанию. Его можно отключить с помощью --ungroup, если Вам нужен вывод в реальном времени (например, для длительных задач с индикаторами выполнения), но тогда перемешивание снова станет возможным.
- По умолчанию: вывод сгруппирован по задачам — безопасен для разбора.
--ungroup: вывод передаётся в реальном времени — удобно для интерактивного мониторинга.--line-buffer: компромиссный вариант — строки никогда не разделяются, но задачи могут перемешиваться на границах строк.
Передача аргументов внутри функций оболочки
Иногда работу, которую Вы хотите выполнить параллельно, нельзя свести к одной команде — это многошаговая функция оболочки. Вы можете передать функцию в parallel, используя export -f вместе с env_parallel, либо напрямую вызвав bash -c.
Самый безопасный переносимый подход для сложных задач — шаблон bash -c '...'. Заполнитель {} передаётся как $1, если завершить команду фрагментом _ {}.
#!/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 {}Ограничение частоты и повторные попытки с --delay и --retries
При параллельном обращении к внешним службам (программным интерфейсам, удалённым серверам, базам данных) часто необходимы ограничение частоты запросов и устойчивость к сбоям.
--delay N— ждать N секунд между запусками очередных задач (допускаются дробные значения, например0.5). Предотвращает перегрузку службы.--retries N— если задача завершается с ненулевым статусом, повторить её до N раз, прежде чем отказаться от выполнения. Каждая повторная попытка занимает новый слот задачи.--timeout N— завершить задачу, если она выполняется дольше N секунд. В сочетании с--retriesэто позволяет корректно обрабатывать зависшие задачи.
Пример: загрузка 50 адресов с не более чем 4 одновременными соединениями, задержкой 0,5 секунды между запусками и 3 повторными попытками при сбое.
#!/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.'Распределение работы между удалёнными узлами с помощью --sshloginfile
parallel может прозрачно распределять задачи между удалёнными машинами через SSH, превращаясь в лёгкий инструмент для кластерных вычислений без специального кластерного программного обеспечения.
--sshlogin user@host— выполнять задачи на определённом удалённом узле.--sshloginfile machines.txt— считывать список узлов из файла (по одному на строку). Используйте:как специальную запись, чтобы также задействовать локальную машину.--transfer— копировать входной файл на удалённый узел перед обработкой.--return {}— копировать файл с результатом обратно после завершения задачи.--cleanup— удалять переданные файлы с удалённого узла после их получения.
На удалённом узле должны быть установлены parallel и настроена аутентификация по ключу SSH (без запросов пароля).
Отображение хода выполнения и ведение журнала
Для длительных вычислений крайне важно отслеживать ход выполнения и впоследствии диагностировать сбои.
--progress— выводить в реальном времени сводную строку с количеством выполняющихся, завершённых и оставшихся задач.--eta— оценивать время до завершения на основе средней продолжительности задач на текущий момент.--joblog results.log— записывать журнал с разделителями-табуляторами, содержащий по одной строке для каждой завершённой задачи, включая код завершения, длительность выполнения и запущенную команду. Незаменимо для проверки сбоев.--resume --joblog results.log— пропускать задачи, которые уже присутствуют в журнале (с кодом завершения 0). Если пакетное выполнение было прервано, его можно продолжить, не повторяя успешно выполненную работу.
Сочетание --joblog + --resume — одна из самых мощных возможностей GNU parallel для надёжных рабочих конвейеров в производственной среде.
#!/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"Проверка знаний: параметры слотов задач
Проверьте, насколько Вы понимаете, как parallel управляет одновременным выполнением.
Итоги урока: оркестрация рабочих нагрузок с GNU parallel
Вы изучили основные инструменты для распределения больших наборов входных данных между ядрами CPU с помощью GNU parallel. Главное:
- Базовое использование: передайте список через конвейер в
parallel command {}—{}заменяется каждым входным элементом. - Слоты задач (
-j): точно управляют одновременным выполнением — используйте число ядер для задач, ограниченных производительностью CPU, и более высокие значения в процентах для задач, ограниченных вводом-выводом. - Заполнители (
{.},{/},{//},{/.}) позволяют без дополнительных команд удобно извлекать компоненты путей. - Управление выводом:
-kсохраняет порядок входных данных; группировка по умолчанию предотвращает перемешивание строк;--ungroupобеспечивает вывод в реальном времени. - Устойчивость:
--retries,--timeoutи--delayделают параллельные конвейеры устойчивыми к нестабильным задачам и ограничениям частоты. - Аудит:
--joblogзаписывает результат каждой задачи;--resumeпозволяет продолжить работу с места остановки после прерывания. - Масштабирование:
--sshloginfileраспределяет задачи между удалёнными машинами через SSH без дополнительных кластерных накладных расходов.
Освоение этих параметров превращает parallel в полноценный оркестратор рабочих нагрузок производственного уровня, встроенный прямо в оболочку.
Часто задаваемые вопросы
Урок «Оркестрация рабочих нагрузок с GNU parallel» бесплатный?
Да — полный текст урока «Оркестрация рабочих нагрузок с GNU parallel» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Linux Command Line & Bash Scripting Mastery, подпишись на CoddyKit PRO. Курс Linux Command Line & Bash Scripting Mastery содержит 4 уроков всего.
Чему я научусь в уроке «Оркестрация рабочих нагрузок с GNU parallel»?
Распределяйте большие наборы входных данных по ядрам с помощью GNU parallel, слотов заданий и упорядочивания результатов Ты практикуешь Linux Command Line & Bash Scripting Mastery с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Linux Command Line & Bash Scripting Mastery?
Предыдущий опыт не требуется. Linux Command Line & Bash Scripting Mastery на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Оркестрация рабочих нагрузок с GNU parallel»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Linux Command Line & Bash Scripting Mastery?
Да. Каждый урок Linux Command Line & Bash Scripting Mastery включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Профилирование скриптов и отказ от ненужных подоболочек
- Параллелизм с xargs -P и фоновыми заданиями
- Оркестрация рабочих нагрузок с GNU parallel
- Потоковые конвейеры и именованные каналы для пропускной способности