GNU parallel
- это инструмент командной строки для параллельного выполнения заданий.
parallel
великолепен и входит в арсенал каждого программиста. Но сначала мне показалось, что документы немного ошеломляют. К счастью, вы можете начать приносить пользу с parallel
с помощью всего лишь нескольких основных команд.
Почему parallel
так полезен?
Давайте сравним последовательное и параллельное выполнение одной и той же ресурсоемкой задачи.
Представьте, что у вас есть папка с аудиофайлами .wav, которые нужно преобразовать в .flac:
Это довольно большие файлы, каждый размером не менее гигабайта.
Мы воспользуемся еще одним замечательным инструментом командной строки, ffmpeg, для преобразования файлов. Вот что нам нужно запустить для каждого файла.
ffmpeg -i audio1.wav audio1.flac
Давайте напишем сценарий для последовательного преобразования каждого из них:
# convert.sh ffmpeg -i audio1.wav audio1.flac ffmpeg -i audio2.wav audio2.flac ffmpeg -i audio3.wav audio3.flac ffmpeg -i audio4.wav audio4.flac ffmpeg -i audio5.wav audio5.flac
Мы можем рассчитать время выполнения задания, добавив time
при вызове скрипта из терминала. time
будет печатать реальное время, прошедшее во время выполнения.
time ./convert.sh
Наш сценарий завершается через чуть больше минуты.
Неплохо. Но теперь давайте запустим его параллельно!
Нам не нужно ничего менять в нашем сценарии. С флагом -a
мы можем направить наш скрипт прямо в parallel
. parallel
будет запускать каждую строку как отдельную команду.
parallel -a ./convert.sh
При использовании parallel
наша конверсия выполнялась чуть более чем за половину времени. Отлично!
Всего с пятью файлами эта разница не такая уж большая проблема. Но с большими списками и более длинными задачами мы можем сэкономить много времени с parallel
.
Я столкнулся с parallel
при работе с задачей обработки данных, которая, вероятно, выполнялась бы в течение часа или более, если бы выполнялась последовательно. С parallel
это заняло всего несколько минут.
parallel
мощность также зависит от вашего компьютера. В моем MacBook Pro Intel i7 всего 4 ядра. Даже эта небольшая задача довела их всех до предела:
Более мощные компьютеры могут иметь процессоры с 8, 16 или даже 32 ядрами, что обеспечивает значительную экономию времени за счет распараллеливания ваших заданий.
Быть полезным с parallel
Другое большое преимущество parallel
- его краткость и простота. Давайте начнем с неприятного скрипта Python и преобразуем его в чистый вызов parallel
.
Вот скрипт Python для преобразования аудиофайлов:
import subprocess path = Path.home()/'my-data-here' for audio_file in list(path.glob('*.wav')): cmd = ['ffmpeg', '-i', str(audio_file), f'{audio_file.name.split(".")[0]}.flac'] subprocess.run(cmd, stdout=subprocess.PIPE)
Ой! На самом деле это большой объем кода, над которым стоит подумать, просто чтобы преобразовать некоторые файлы. (Это занимает около 1,2 минуты).
Давайте преобразуем наш Python в parallel
.
Вызов скрипта с parallel -a
parallel -a your-script-here.sh
- прекрасный однострочный файл, который мы использовали выше для конвейерной передачи в нашем сценарии bash.
Это замечательно, но требует, чтобы вы написали сценарий bash, который хотите выполнить. В нашем примере мы по-прежнему записывали каждый отдельный вызов ffmpeg
в convert.sh
.
Трубы и интерполяция строк с parallel
К счастью, parallel
дает нам возможность полностью удалить convert.sh
.
Вот все, что нам нужно сделать, чтобы совершить конверсию:
ls *.wav | parallel ffmpeg -i {} {.}.flac
Давайте разберемся с этим.
Мы получаем список всех файлов .wav в нашем каталоге с ls *.wav
. Затем мы передаем (|
) этот список на parallel
.
Parallel предоставляет несколько полезных способов интерполяции строк, поэтому пути к нашим файлам вводятся правильно.
Первый - это {}
, который parallel
автоматически заменяется одной строкой из нашего ввода.
Второй оператор - {.}
, который вводит одну строку, но с удаленными расширениями файлов.
Если бы мы расширили команду, выполняемую parallel
для нашей первой строки ввода, мы бы увидели ...
ffmpeg -i audio1.wav audio1.flac
Аргументы с Parallel
Как оказалось, нам даже не нужно подключаться к ls
, чтобы выполнить нашу задачу. Мы можем пойти еще проще:
parallel ffmpeg -i {} {.}.flac ::: *.wav
Аргументы, переданные в parallel
, появляются после команды и разделяются :::
. В этом случае нашим аргументом является *.wav
, который предоставит список всех файлов .wav в нашем каталоге. Эти файлы становятся исходными данными для нашей молниеносной parallel
работы.
Интересный факт: parallel
был построен Ole Tange и опубликован в 2011 году. По его словам, вы можете использовать инструмент для исследования, не ссылаясь на исходный текст, за скромную плату в 10 000 евро!
Спасибо за прочтение!