- Руководство по использованию GNU Parallel
- Оглавление
- 1. Инструкция по использованию Parallel
- Что такое GNU Parallel
- Как установить GNU Parallel
- 2. Основы Parallel
- Файлы для тестовых запусков программ
- Синтаксис запуска Parallel
- Источники ввода
- Построение строки команды
- Проверка сгенерированных команд без их запуска
- Контроль вывода
- Контроль выполнения
- Режим Pipe (передача данных по трубе из других программ)
- 3. Новые тестовые файлы
- 4. Источники ввода
- Один источник ввода
- Несколько источников ввода
- Попарное использование аргументов из различных источников ввода
- Изменение разделителя аргументов
- Изменение разделителя записей
- Значение конец-файла для источника ввода
- Пропуск пустых строк
- 5. Построение строки команды
- Отсутствие команды означает, что аргументы являются командами
- Строки замены (подстановки)
- Вставка более чем одного аргумента
- Помещение строки команды в кавычки
- Обрезка пробелов из аргументов
- Работа в различных оболочках
- 6. Контроль вывода
- Добавление тэга перед выводом
- Просмотр генерируемых команд без их запуска
- Принудительный порядок в соответствии с вводом
- Вывод до завершения работы
- Сохранение вывода в файлы
- Сохранение в CSV/TSV
- Сохранение в SQL базу данных
- Сохранение вывода в переменные оболочки
- 7. Контроль выполнения
- Количество одновременных работ
- Перемешивание последовательности работ
- Интерактивность
- Терминал для каждой работы
- Тайминги
- Информация о прогрессе
- Файл журнала
- Возобновление работ
- Прекращение работы
- Перезапуск неудачных команд
- Сигналы терминации
- Ограничение ресурсов
- Создание своих собственных ограничений
Руководство по использованию GNU Parallel
Оглавление
8. Удалённое выполнение
9. Режим Pipe (передача данных по трубе)
10. Прочие функции
1. Инструкция по использованию Parallel
Что такое GNU Parallel
GNU parallel — это инструмент оболочки для параллельного выполнения работ используя один или более компьютер.
В качестве работы может быть единичная команда или небольшой скрипт, который должен быть запущен для каждой строки из полученного ввода. Типичным вводом является список файлов, список хостов, список пользователей, список URL, список таблиц. В качестве работы может быть команда, которая считывает по трубе (pipe). GNU parallel затем может разбить ввод на блоки и передать блоки по трубе параллельно в каждую команду.
GNU parallel может заменить вам программы xargs и tee. А также не только заменить циклы (loops), но и сделать их выполнение более быстрым за счёт параллельного выполнения нескольких работ.
У программы много опцией, в том числе для контролирования ввода и вывода. Также программа может контролировать запуск новых работ в зависимости от доступных системных ресурсов (свободная оперативная память и загруженность центрального процессора).
Как установить GNU Parallel
Parallel присутствует в стандартных репозиториях популярных дистрибутивов Linux.
Для установки в Debain, Linux Mint, Ubuntu, Kali Linux и их производных выполните:
Для установки в Arch Linux, BlackArch и их производных выполните:
2. Основы Parallel
Файлы для тестовых запусков программ
Чтобы показывать работу программы на конкретных примерах, которые вы можете повторять, выполните следующую команду:
В результате будет создано пять файлов вида example.1..5.
Синтаксис запуска Parallel
При получении аргументов из стандартного ввода команда запускается так:
При указании аргументов в строке команды:
Источники ввода
Поскольку по своей функции программа Parallel подразумевает, что ею будет запущено несколько экземпляров другой программы, то при запуске нужно указать ту другую программу и аргументы к ней, пример простого случая запуска Parallel:
Как можно увидеть, аргументы от запускаемой программы отделены тремя символами двоеточия, то есть . . Пример запуска пяти экземпляров программы echo у каждого из которого будет свой аргумент (одна цифра):
Обратите внимание, что в данном и большинстве последующих примеров порядок вывода может быть другим от указанного в примерах, поскольку разные экземпляры запускаемой команды могут закончить работу в разное время.
Также обратите внимание, что разделителем является пробел. Если вам нужно использовать пробел в передаваемом значении, то его нужно экранировать, либо взять передаваемое значение в кавычки:
В качестве передаваемых аргументов могут быть файлы, например:
Если разделитель . указать несколько раз, то GNU Parallel сгенерирует все возможные комбинации:
GNU Parallel также может считывать значения из stdin (стандартного ввода):
Как можно увидеть, в этом случае не используется последовательность . , и если уже есть другие аргументы (в данном случае это строка «Файл»), то аргументы из стандартного ввода добавляются в конец строки.
Построение строки команды
Строка запускаемой команды размещается перед . . Она может содержать команду и опции для этой команды:
Команда может содержать несколько программ. Но помните экранировать символы, которые имеют для оболочки особое значение, например:
Опции добавляются к концу команды (после опций), но вы можете разместить их в любом месте, используя строку заполнитель <> :
При использовании нескольких источников ввода, вы можете использовать позиционные (пронумерованные) строки заменители и :
Проверка сгенерированных команд без их запуска
С опцией —dry-run вы моежте проверить, что именно будет запущено, но фактический запуск сделан не будет:
Пока вы находитесь в процессе изучения GNU Parallel, то эта опция поможет вам делать отладку вашей команды, также она поможет избежать возможных проблем.
Контроль вывода
Вывод будет напечатан сразу после завершения работы программы. Это означает, что вывод может следовать в отличном от ввода порядке:
Опцией —keep-order / -k вы можете принудить Parallel печатать в том же порядке что и введённые значения. Команды всё равно будут запущенны параллельно, но вывод результатов более поздних работ будет отложен пока не будут напечатаны результаты более ранних работ:.
Контроль выполнения
Если ваши работы требуют интенсивных вычислений, то весьма вероятно, что вы захотите запускать одну работу на одно ядро системы. GNU Parallel работает так по умолчанию.
Но иногда вам может понадобиться больше запущенных работ, контролировать номера слотов работ вы можете опцией -j / —jobs. Укажите с —jobs количество работ для параллельного запуска. Здесь мы запускаем 2 в параллели:
Два слота работ должны запустить 5 работ, которые выполняются 1-5 секунд. В начале одновременно выполняются работы, требующие 5 и 4 секунды, затем одновременно выполняются работы требующие 3 и 1 секунду, последней выполняется работа, требующая 2 секунды.
Если вместо этого запустить параллельно 5 работ, все 5 работ будут запущены в одно и то же время и завершаться в различное время:
Вместо указания количества работ для запуска, вы можете передать —jobs 0 и в результате будет запускаться так много параллельных работ, сколько возможно.
Режим Pipe (передача данных по трубе из других программ)
GNU Parallel может также передавать блоки данных командам в stdin (стандартном вводе):
Это может использоваться для обработки больших текстовых файлов. По умолчанию Parallel разбивает по \n (newline) и передаёт блоки примерно по 1 МБ каждой работе.
3. Новые тестовые файлы
Для дальнейших примеров нам понадобятся дополнительные тестовые файлы. Их можно сгенерировать следующим образом:
4. Источники ввода
GNU Parallel считывает вводимые данные из источников ввода. Ими могут быть файлы, командная строка stdin (стандартный ввод или труба).
Один источник ввода
Ввод может быть считан из командной строки:
Источником ввода может быть файл:
Вывод: такой же, как выше.
Источником ввода может быть stdin (стандартный ввод):
Вывод: такой же, как выше.
Файлом также может быть и FIFO:
Вывод: такой же, как выше.
Или подстановка команды Bash/Zsh/Ksh:
Вывод: такой же, как выше.
Несколько источников ввода
GNU Parallel может принимать в командной строке несколько заданных источников ввода. Тогда Parallel генерирует все комбинации источников ввода:
Источниками ввода могут быть файлы:
Вывод: такой же, как выше.
Stdin (стандартный ввод) может быть одним из источников ввода при использовании — :
Вывод: такой же, как выше.
Вместо использовании опции -a после которой идёт имя файла, этот файл можно указать после . (четыре двоеточия) :
Вывод: такой же, как выше.
Можно использовать . и . одновременно:
Вывод: такой же, как выше.
Попарное использование аргументов из различных источников ввода
С опцией —link вы можете задать попарное использование аргументов, пришедших из разных источников ввода (вместо построения всех возможных комбинацией):
Если один из источников ввода слишком короткий, то его значения будут использоваться по кругу:
Для более гибкого связывания вы можете использовать . + и . + . Они работают как . и . за исключением того, что они привязывают предыдущий источник ввода к этому источнику ввода.
Следующая команда привяжет ABC к GHI:
Эта команда привяжет GHI к DEF:
Если один из источников ввода слишком короткий при использовании . + или . + , то недостающая для связывания часть будет проигнорирована:
Изменение разделителя аргументов
Вместо . или . GNU Parallel может использовать другие разделители. Это обычно полезно если . или . используется в команде для запуска:
Изменение разделителя файлового аргумента:
Вывод: такой же, как предыдущий.
Изменение разделителя записей
GNU Parallel в обычных условиях трактует целую строку как единичную запись: она использует в качестве разделителя записей \n.
С помощью опции -d можно изменить это поведение:
NUL может быть задан как \0 :
Вывод: такой же, как предыдущий.
Сокращением для -d ‘\0’ является -0 (это часто используется для чтения файлов от find … -print0 ):
Вывод: такой же, как предыдущий.
Значение конец-файла для источника ввода
GNU Parallel может остановить чтение когда она сталкивается с определённым значение:
Пропуск пустых строк
Используя опцию —no-run-if-empty вы можете сделать так, что Parallel будет пропускать пустые строки.
5. Построение строки команды
Parallel по умолчанию запускает команды на основе шаблона в который подставляет значения из источников ввода.
Отсутствие команды означает, что аргументы являются командами
Если команды не даны, то сами аргументы parallel трактует как команды:
В качестве команды может быть скрипт, бинарный файл или функция Bash если функция экспортирована с использованием export -f:
Если вы используете env_parallel (смотрите далее раздел Трансфер переменных окружения и функций), то вы также можете использовать псевдонимы.
Строки замены (подстановки)
Предопределённые 7 строк замены
GNU Parallel имеет несколько строк замены. Предопределены 7 следующих:
Строка замены | Значение |
---|---|
<> | mydir/mysubdir/myfile.myext |
mydir/mysubdir/myfile | |
> | myfile.myext |
/> | mydir/mysubdir | myfile |
последовательный номер работы | |
номер слота работы |
Если в команде не используются строки замены, то по умолчанию добавляется <>. Если в команду передаётся строка, то <> означает эту строку, если передаётся имя файла, то означает полный путь до этого файла (как показано в таблице).
Дефолтной строкой замены является <>:
Строка замены удаляет расширение:
Строка замены > удаляет путь:
Строка замены /> оставляет только путь:
Строка замены удаляет путь и расширение:
Строка замены передаёт номер работы. При запуске каждой работы они получают последовательные номера, которые начинаются на 1 и увеличиваются на 1 для каждой новой работы.
Строка замены передаёт номер слота работы (между 1 и числом запущенных параллельно работ). Каждой работе назначает номер слота. Это номер от 1 до номера параллельно запущенных работ. Он уникален между работающими задачами, но повторно используется как только какая-либо работа завершается.
При вставке строка замены помещается в кавычки. Поэтому не нужно беспокоиться об экранировании специальных символов:
Если вы не хотите помещать строку в кавычки, то вы можете использовать eval:
Использование других строк замены
Строка замены <> может быть поменяна опцией -I:
Строка замены может быть поменяна опцией —extensionreplace:
Строка замены > может быть поменяна опцией —basenamereplace:
Строка замены /> может быть поменяна опцией —dirnamereplace:
Строка замены может быть поменяна опцией —basenameextensionreplace / —bner:
Строка замены может быть поменяна опцией —seqreplace:
Строка замены может быть поменяна опцией —slotreplace:
Выражения Perl в качестве строки замены
Если предопределённые строки замены недостаточно гибки, можно вместо них использовать выражения perl. Этот пример удаляет два расширения: foo.tar.gz становится foo
Функции для perl выражений в качестве строк замены
В вы можете получить доступ ко всем внутренним функциям и переменным GNU Parallel. Несколько из них стоит упомянуть.
total_jobs() возвращает общее число работ:
slot() возвращает слот работы:
seq() возвращает последовательный номер работы:
Q(…) помещает строку в кавычки:
pQ(…) perl помещает строку в кавычки, что полезно если строка замены используется как часть строки Perl и вы не хотите чтобы Perl делал на ней подстановку:
skip() пропускает работу:
@arg содержит переменные источников ввода:
Если строка <=и => вызывают проблемы, то она может быть заменена с опцией —parens:
Чтобы задать сокращение строки замены используйте опцию —rpl:
Вывод: такой же, как и выше.
В Parallel предопределённые 7 строк замены реализованы следующим образом:
Строка замены | Код |
---|---|
<> | |
s:\.[^/.]+$:: | |
> | s:.*/:: |
/> | $Global::use <"File::Basename">||= eval «use File::Basename; 1;»; $_ = dirname($_); | s:.*/::; s:\.[^/.]+$::; |
$_=$job->seq() | |
$_=$job->slot() |
Динамически заменяемые строки
Если в фигурных скобках содержаться парные круглые скобки, то строка замены становится динамической строкой замены, и к строке в круглых скобках можно обратиться как $$1. Если имеется несколько парных круглых скобок, то совпадающие строки будут доступны по $$2, $$3 и так далее.
Вы можете думать об этом как оп ередаче аргументов к строке замены. Здесь мы передаём аргумент .tar.gz строке замены , которая удаляет string:
Здесь мы передаём два аргумента tar.gz и zip в строку замены , которая заменяет string1 на string2:
Позиционные строки замены
С несколькими источниками ввода аргумент от индивидуального источника ввода может быть получен по :
Позиционная строка замены также может быть модифицирована использованием / , // , /. , и ..
Строка замены | Значение |
---|---|
mydir/mysubdir/myfile.myext | |
mydir/mysubdir/myfile | |
<3/> | myfile.myext |
<3> | mydir/mysubdir |
<3> | myfile |
Если позиция обозначена отрицательным числом, то она будет обращена к источнику ввода, посчитанному с конца:
Выражения perl как позиционные строки замены
Для использования выражений perl в качестве позиционной строки замены просто поставьте перед выражением perl число и пробел:
Если шортхэнд, определённый опцией —rpl, начинается с <, он также может использоваться как позиционная строка замены:
Вывод: такой же, как выше.
Ввод из колонок
Столбцы в файле, при использовании опции —colsep, могут быть привязаны к позиционным строкам замены. Здесь колонки разделены ТАБОМ (\t):
Строки замены с предопределёнными заголовками
С опцией —header GNU Parallel будет использовать первое значение источника ввода в качестве имени строки замены. Поддерживается только немодифицирующая опция <>:
Она используется с —colsep для обработки файлов со величинами, разделёнными ТАБОМ:
Больше предопределённых строк замены с —plus
Опция —plus добавляет строки замены <+/> <+.> <+..> <+…>. Идея в том, что соответствует противоположности и <> = <+/> / > = . = <+/> / . = . = <+/> / . = . = <+/> / . .
это общее число работ:
Динамическая строка замены с —plus
—plus также определяет следующие динамические строки замены:
Строка замены | Значение | Похожее в Bash |
---|---|---|
Если аргумент является пустым, то значением по умолчанию является строка. | $ | |
Подстрока от числа до конца строки. | $ | |
Подстрока от числа1 до числа2. | $ | |
Если аргумент начинается со строки, удалить его. | $ | |
Если аргумент заканчивается на строку, удалить его. | $ | |
строка1/строка2> | Заменить строку1 на строку 2. | $ |
Если аргумент начинается на строку, перевести её в верхний регистр. Строка должна быть единичным символом. | $ | |
Если аргумент содержит строку, перевести её в верхний регистр. Строка должна быть единичным символом. | $ | |
Если аргумент начинается со строки, перевести его в нижний регистр. Строка должна быть единичным символом. | $ | |
Если аргумент содержит строку, перевести её в нижний регистр. Строка должна быть единичной буквой. | $ |
Они вдохновлены аналогичным синтаксисом в Bash:
Вставка более чем одного аргумента
С опцией —xargs Parallel вставит так много аргументов, сколько это возможно для одной строки:
30000 аргументов распределены на 2 строки команды: 23690 аргументов для первой команды и 6310 для второй.
Максимальная длина одной строки может быть установлена с -s. С максимальной длинной в 30000 символов, 6 команд будут запущены с примерно 5000 аргументами для каждой команды:
Для лучшего параллелизма, GNU Parallel может распределять аргументы между всеми параллельными работами когда встречается конец-файла.
Ниже Parallel считывает последний аргумент при генерации второй работы. Когда Parallel считывает последний аргумент, она распределяет все аргументы для второй работы по 4 работам поскольку запрошены 4 параллельных работы.
При использовании -m первая работа будет такой же, как и с опцией —-xargs пример с которой показан выше, но вторая работа будет разбита на 4 одинаковых по размеру работы, в результате всего будет 5 работ:
Ещё более наглядно при запуске 4 работ с 10 аргументами. 10 аргументов будут распределены по 4 работам:
Строка замены может быть частью слова. Опция -m не будет повторять контекст, который соприкасается со строкой замены:
Для повторения контекста используйте переключатель -X, который в противном случае работает как -m:
Для ограничения количества аргументов используйте опцию -N:
-N также устанавливает позиционные строки замены:
-N0 считывает 1 аргумент, но ничего не вставляет:
Это полезно для параллельного запуска одной и той же команды много раз.
Помещение строки команды в кавычки
Строки команд, содержащих специальные символы, может понадобиться защитить от интерпретации их оболочкой.
Программа perl печатает «@ARGV\n» в основе работает как echo.
Для запуска её в параллели она требует быть помещённой в кавычки:
Для помещения команды в кавычки, используйте опцию -q:
Вы можете поместить в кавычки критическую часть используя \’ :
GNU Parallel также может \ -quote целые строки. Просто запустите это:
и нажмите [CTRL-D]
Это можно использовать в качестве команды:
Обрезка пробелов из аргументов
Если вам нужно обрезать конечные пробелы, то используйте опцию —trim:
Удаление пробелов с левой стороны:
Удаление пробелов с обеих сторон:
Работа в различных оболочках
Это руководство использует в качестве оболочки Bash. GNU Parallel учитывает то, какую оболочку она использует, то есть в zsh вы можете делать:
В csh вы можете делать:
Это также становится полезным если вы используете GNU Parallel в скрипте оболочки: Parallel будет использовать ту же самую оболочку, что и скрипт оболочки.
6. Контроль вывода
По общему правилу GNU Parallel печатает вывод от работы когда она завершена.
Добавление тэга перед выводом
Перед каждой строкой вывода можно добавить значение аргумента:
—tag это сокращение —tagstring <>. Чтобы указать в качестве префикса другую строку, используйте —tagstring:
Просмотр генерируемых команд без их запуска
Чтобы узнать, какие команды будут запущены, но при этом их не запускать, используйте опцию —dryrun:
Чтобы вывода команд перед их запуском используйте флаг —verbose:
Но эта информация соответствует действительности не во всех случаях — при использовании —nice, —pipepart, или когда работа запускается на удалённой машине, то команда оборачивается в дополнительный код. Подробности будут рассмотрены в конце раздела Удалённое выполнение.
Принудительный порядок в соответствии с вводом
принимает в качестве аргумента число (#). Она печатает полную строку ‘#-начало’ за которой следует половина строки ‘#’. Затем она засыпает на # секунд, далее печатает ‘-середина’ за которой следует ‘#-конец’.
Чтобы сделать так, чтобы вывод разных команд не перемешивался и следовал один за другим в таком же порядке как и аргументы, используйте флаг —keep-order / -k:
Вывод до завершения работы
GNU Parallel откладывает вывод пока команда не завершиться:
Это из-за того, что опция —group включена по умолчанию. Для немедленного получения вывода, используйте опцию —ungroup / -u:
—ungroup является быстрой, но отключает —tag и может быть причиной разрыва строк и перемешивания вывода от разных работ даже на одной строке. Это произошло на второй строке последнего примере, где перемешены строки «42-начало» и «-середина».
Чтобы избежать этого, используйте опцию —linebuffer, с которой программа будет выводить только полные строки:
С —keep-order —line-buffer GNU Parallel будет последовательно выводить строки от первой работы, пока она не завершиться, затем GNU Parallel будет последовательно выводить строки от второй работы пока она работает. Она будет помещать в буфер целые строки, но вывод от разных работ не будет смешиваться.
Буферизация на диск
Parallel использует в качестве буфера временные файлы. Если у программы больше вывода, чем свободного места на диске, то при использовании —group или —line-buffer —keep-order диск будет заполнен. Это не происходит при использовании —line-buffer без —line-buffer (которая сохраняет в буфер одну строку в оперативной памяти) и —ungroup (которая вовсе не использует буфер).
Сохранение вывода в файлы
GNU Parallel может сохранять вывод для каждой работы в файлы:
Вывод будет примерно таким:
По умолчанию Parallel кэширует вывод в файлы в /tmp. Это можно изменить установкой $TMPDIR или —tmpdir:
Вывод будет примерно таким:
Вывод: такой же, как предыдущий.
С использованием опции —results файлы могут быть сохранены структурировано:
Также генерируются файлы, содержащие стандартный вывод (stdout), стандартный вывод ошибок (stderr) и последовательный номер (seq):
Опция —header примет первое значение в качестве имени и использует его в структуре директории. Это полезно при использовании нескольких источников ввода:
Директории называются по переменным и их значениям.
Если аргумент для —results содержит строку замены, stdout будет сохранён под этим именем:
Если аргумент для —results содержит строку замены и оканчивается на / , вывод будет сохранён в директорию с этим именем:
Сохранение в CSV/TSV
Многие программы поддерживают файлы Значений разделённых запятой (Comma Separated Values)/Значений, разделённых ТАБОМ (Tab Separated Values). И Parallel не является исключением. Если аргумент для —results оканчивается на .csv или .tsv, то в качестве вывода будет файл CSV/TSV.
Это быстрее, чем использование CSV в качестве SQL базы данных.
Сохранение в SQL базу данных
Parallel может сохранять в SQL базу. Укажите GNU Parallel на таблицу и она поместит туда лог работы вместе с переменными и выводом — каждый в своём собственном столбце.
CSV как SQL база
Самое простое это использование CSV в качестве таблицы хранилища:
Обратите внимание, что ‘/‘ в пути должна быть записана как %2F.
Вывод будет примерно таким:
Первая колонка хорошо известна по опции —joblog. V1 и V2 это данные из источников ввода. Stdout и Stderr это, соответственно, стандартный вывод и стандартный вывод ошибок.
Программы, которые умеют работать с CSV (такие как LibreOffice или команда read.csv из R) прочитают этот формат корректно — даже если поля содержат переносы строк как в примере выше.
Если вывод велик вы можете захотеть поместить его в файлы используя —results. В этом случае CSV файл будет содержать имена файлов:
Вывод примерно такой:
DBURL в качестве таблицы
Файл CSV это пример DBURL.
GNU Parallel использует DBURL для адресации к таблицам. DBURL имеет следующий формат:
Для указания на /tmp/mydatabase с sqlite или csv вам нужно кодировать / на %2F.
Запуск работы используя sqlite на mytable в /tmp/mydatabase:
Для просмотра результатов:
Вывод будет примерно таким:
Использование нескольких воркеров
Использование SQL базы в качестве хранилища требует дополнительных затрат порядка 1 секунды на задание. Одна из ситуаций, где это имеет смысл, когда вы должны использовать несколько воркеров.
Вы можете иметь один главный компьютер, который отправляет задания в SQL базу (но который не выполняет никакой работы):
На машине-воркере (где выполняется задача) вы можете запустить в точности такую же команду, за исключением того, что вы заменяете —sqlmaster на —sqlworker.
Для запуска мастера и воркера на одной и той же машине используйте —sqlandworker как это показано ранее.
Экземпляр запущенный с —sqlmaster выйдет как только работы помещены в базу данных (если не указана опция —wait). Эта опция сделает так, что машина с —wait перед выходом будет ждать завершение всех работ.
Вы можете добавить больше работ в существующую таблицу поставив + перед DBURLTABLE:
Сохранение вывода в переменные оболочки
GNU Parset установит переменные оболочки для вывода GNU Parallel. GNU Parset имеет одно важное ограничение: он не может быть частью трубы. В частности, это означает, что он ничего не может прочитать из стандартного ввода (stdin) или конвейерного (по трубе) вывода в другую программу.
GNU Parset — это функция оболочки. Для её активации:
После этого будет запущена новая оболочка.
Parset поддерживается для bash, dash, ash, sh, ksh и zsh .
Для использования parset поместите переменные назначения перед обычными опциями и командой GNU Parallel:
Если вы передали только одну переменную, она будет трактоваться как массив:
Командами для запуска может быть массив:
Чтение из трубы (конвейерный ввод)
GNU Parset не может читать из трубы поскольку сама программа запускается в под-оболочке и, следовательно, вывод не будет виден в запустившей оболочке. Для обхода этой проблемы имеется несколько вариантов.
Использование временного файла
Вместо чтения непосредственно из трубы, сохраните вывод в файл и затем пусть parset прочитает его:
Использование подстановку процесса
Если ваша оболочка поддерживает подстановку процесса (Bash, Zsh и Ksh это могут), тогда вы можете использовать следующее:
Если количество данных великов или вам нужно, чтобы GNU Parset начал читать до того, как сгенерирован весь вывод, то вариантом может быть использование FIFO.
env_parset будет делать то же самое, что и parset, но используя env_parallel (смотрите далее Передача переменных окружения и функций) вместо parallel, поскольку вам понадобиться доступ к псевдонимам, неэкспортируемым функциям и неэкспортируемым переменным.
7. Контроль выполнения
По умолчанию GNU Parallel запускает параллельно одну работу на каждое ядро центрального процессора и завершается когда все работы выполнены.
Количество одновременных работ
Количество параллельных работ указывается с опцией —jobs / -j (-N0 считывает единичный аргумент, но ничего не вставляет — поэтому он запускает параллельно много раз sleep 1):
С 64 работами в параллели, 128 sleep потребуют 2-8 секунды для работы — зависит от того, насколько быстрая ваша машина.
По умолчанию значение опции —jobs равно количеству ядер CPU. Поэтому это:
должно занять в два раза больше времени на запуск 2 работ на каждое ядро центрального процессора:
—jobs 0 запустит так много одновременных работ, насколько это возможно:
/usr/bin/time parallel -N0 —jobs 0 sleep 1 . num128
это займёт 1-7 секунд в зависимости от того, насколько быстрая у вас машина.
—jobs может читать из файла и перечитывать когда работа завершена:
GNU Parallel при запуске считает my_jobs. Он содержит значение 50% поэтому Parallel будет делать вычисления на 50% числа ядер и запустит это количество работ в параллели.
Из-за символа & программа Parallel будет запущена в фоне.
После одной секунды в my_jobs сохраняется 0. Когда работа закончена, Parallel повторно считывает my_jobs, и затем Parallel запускает так много работ, как возможно.
Указанные проценты применяются к количеству ядер центрального процессора, но с помощью соответствующей опции можно сделать так, что Parallel за основу возьмёт количество центральных процессоров:
Перемешивание последовательности работ
Если у вас много работ (к примеру много комбинаций источников ввода), то может быть полезным перемешать работы, чтобы они выполнялись в случайном порядке. Для этого используйте опцию —shuf:
Вывод: все комбинации, но при каждом запуске порядок будет разный.
Интерактивность
Parallel может спрашивать пользователя, должна ли команда быть запущена, для этого используется опция —interactive:
Parallel может использоваться для помещения аргументов в командную строку для интерактивных команд, таких как emacs для редактирования одно файла за раз:
Или передачи нескольких аргументов за один проход в несколько открытых файлов:
Терминал для каждой работы
При использовании —tmux программа Parallel может открыть терминал для каждой запускаемой работы:
Это скажет вам запустить что-то вроде:
Используя комбинации клавиш tmux (CTRL-b n или CTRL-b p) вы можете переключаться по кругу между окнами запущенных работ. Когда работа завершается, она ставится на паузу на 10 секунд перед закрытием окна.
Чтобы Parallel оставляла открытым окно каждой работы в своей собственной панели, используйте —tmuxpane. —fg немедленно подключится к tmux:
parallel —tmuxpane —fg ‘echo start <>; sleep <>; echo done <>‘ . 10 11 12 13 14 15 16 17
Тайминги
Некоторые работы при запуске интенсивно читают или пишут на диск. Чтобы избежать проблем из-за этого, Parallel может задерживать запуск новых работ. Опция —delay X сделает так, что будет по крайней мере X секунд между каждым стартом:
Если работы занимают больше времени чем должны при нормальной работе, то они могут быть остановлены по таймауту опцией —timeout. Точность —timeout составляет 2 секунды. —timeout 100000 можно записать как —timeout 1d3.5h16.6m4s.
GNU Parallel может рассчитывать медианное время выполнение для работ и закрывать те, которые потребляют более 200% медианного времени выполнения:
Это полезно если с некоторыми работами что-то пошло не так и им нужно намного больше времени чем остальным работам.
Информация о прогрессе
На основе времени выполнения завершённых работ Parallel может прикинуть общее время выполнения:
Parallel с опцией —progress покажет информацию о прогрессе:
Опция —bar используется для вывода полосы прогресса:
И графическая полоса програссе может быть показана с —bar и zenity:
Файл журнала
Для закончивших выполнение работ с помощью опции —joblog можно сгенерировать лог:
Журнал содержит последовательность работ, хост, на котором они были запущены, время старта и время работы, как много данных было передано, статус выхода, сигнал, который убил работу и, наконец, команду, которая была запущена.
Возобновление работ
При запуске с —joblog, Parallel может быть остановлена до окончания всех работ и затем запущена с того же самого места. Важно, чтобы ввод завершённых работ был неизменным.
Обратите внимание, что время запуск последних 2 работ явно отличается от первого запуска.
С опцией —resume-failed GNU Parallel перезапустит работы, которые завершились неудачей:
Обратите внимание, как были повторены seq 1 2 3 поскольку они имели значение статуса выхода отличное от 0.
Опция —retry-failed делает почти то же самое, что и —resume-failed. Опция —resume-failed считывает команды из командной строки (и игнорирует команды от —joblog), —retry-failed игнорирует командную строку и возвращает команды, упомянутые в —joblog.
Прекращение работы
Безусловное прекращение работы
По умолчанию перед своим выходом Parallel ожидает все работы когда они завершаться.
Если вы отправили в Parallel сигнал TERM, то Parallel прекратит запускать новые работы и будет ждать ожидания уже запущенных работ. Если вы вновь отправили в Parallel сигнал TERM, то Parallel убьёт все запущенные работы и отключится.
Остановка в зависимости от статуса работы
Для определённых работ не нужды продолжать, если одна из работ завершилась неудачей и имет код выхода отличный от 0. GNU Parallel прекратит запуск новых работ с опцией —halt soon,fail=1, например:
Если значение —halt указано в процентах, то этот процент работ должен завершиться неудачей перед тем, как GNU Parallel остановит запуск новых работ:
Если вместо неудачных запусков вы ищите успешные. Следующий пример завершиться как только появится первая удачно завершившаяся работа.
Если вас не волнует значение выхода, но вы хотите просто 3 завершённых работы, вы можете использовать опцию done=3:
Перезапуск неудачных команд
GNU Parallel может повторно запустить команды при использовании опции —retries. Это полезно если команда время от времени неудачно завершается по неизвестным причинам.
Обратите внимание, что работа 1 и 2 были запущены 3 раза, но 0 не была запущена вновь, поскольку у неё код статуса выхода равен 0.
При использовании с удалённым выполнением (смотрите далее), то если это возможно, работа будет запущена на другом сервере.
Сигналы терминации
Используя опцию —termseq вы можете контролировать, какие сигналы отправляются, когда завершаются дочерние процессы. По умолчанию дочерние процессы завершаются отправкой им SIGTERM, ожидаем 200 ms, затем другим SIGTERM, ожиданием 100 ms, затем другим SIGTERM, ожиданием 50 ms, затем SIGKILL, и конечным ожиданием 25 ms перед прекращением попыток. Это выглядит примерно так:
Вывод: такой же, как и предыдущий.
Вы можете заменить сигналы на SIGINT, SIGTERM, SIGKILL:
SIGKILL не показан, поскольку он не может быть перехвачен, но дочерний процесс всё равно завершается.
Ограничение ресурсов
Parallel может запускать работы со означением nice (что-то вроде приоритета процесса при потреблении ресурсов центрального процессора). Это работает как локально, так и удалённо.
Чтобы избежать перегрузки системы, Parallel перед запуском ещё следующей работы может свериться с системными ресурсами:
Parallel также может проверить, использует ли система раздел подкачки.
Некоторым работам требуется много оперативной памяти и они должны быть запущены только если достаточно свободной памяти. При использовании опции —memfree Parallel может проверить, достаточно ли свободной памяти. Дополнительно Parallel убьёт самую молодую работу, если количество свободной памяти стало менее 50% размера. Убитая работа будет возвращена в очередь и если указана опция —retries, то будет сделана попытка запустить её вновь.
Создание своих собственных ограничений
С опцией —limit вы можете создавать свои собственные ограничения наподобие —memfree и —load. Вам просто нужно сделать программу, которая возврарщает: