Как улучшить рабочие процессы bash с помощью GNU parallel

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работы.

Fun fact: parallel was built by Ole Tange and published in 2011. According to him, you can use the tool for research without citing the source paper for the modest fee of 10,000 euros!

Thanks for reading!