Выбрать главу

Сценарий в листинге Б.3 демонстрирует, как распараллелить заданную команду по нескольким процессам, выполняющимся одновременно.

ПРИМЕЧАНИЕ

Если ваш компьютер оснащен одноядерным процессором или выбранная программа работает медленно по другим причинам, например из-за невысокой скорости доступа к жесткому диску, запуск сразу нескольких экземпляров программы только ухудшит производительность. Будьте осторожны, не запускайте слишком много процессов, так как это легко может застопорить маломощную систему. К счастью, даже Raspberry Pi имеет несколько ядер!

Код

Листинг Б.3. Сценарий bulkrun

··#!/bin/bash

··# bulkrun — выполняет обход файлов в каталоге и запускает несколько

··#·· процессов для их одновременной обработки.

··printHelp()

··{

····echo "Usage: $0 −p 3 −i inputDirectory/ −x \"command −to run/\""

····echo −e "\t-p The maximum number of processes to start concurrently"

····echo −e "\t-i The directory containing the files to run the command on"

····echo −e "\t-x The command to run on the chosen files"

····exit 1

··}

··while getopts "p: x: i: " opt

··do

····case "$opt" in

······p) procs="$OPTARG"····;;

······x) command="$OPTARG"··;;

······i) inputdir="$OPTARG";;

······?) printHelp··········;;

····esac

··done

··if [[-z $procs || −z $command || −z $inputdir]]

··then

····echo "Invalid arguments"

····printHelp

··fi

··total=$(ls $inputdir | wc −l)

··files="$(ls −Sr $inputdir)"

··for k in $(seq 1 $procs $total)

··do

····for i in $(seq 0 $procs)

····do

······if [[$((i+k)) −gt $total]]

······then

········wait

········exit 0

······fi

······file=$(echo "$files" | sed $(expr $i + $k)"q;d")

······echo "Running $command $inputdir/$file"

······$command "$inputdir/$file"&

····done

····wait

··done

Как это работает

Сценарий bulkrun принимает три аргумента: максимальное количество процессов, действующих в каждый конкретный момент времени , каталог с файлами для обработки и команду для запуска (в конец которой добавляется имя файла для обработки) . После чтения пользовательских аргументов с помощью getopts сценарий убеждается в наличии всех трех обязательных аргументов. Если любая из переменных −procs, command или inputdir — осталась неопределенной, сценарий выводит сообщение об ошибке , текст справки и завершает выполнение.

После проверки переменных, необходимых для управления запуском параллельных процессов, сценарий приступает к выполнению фактической работы. Для начала определяется количество обрабатываемых файлов , и их список сохраняется для дальнейшего использования. Затем сценарий входит в цикл for, который следит за количеством файлов, обработанных к текущему моменту. Команда seq используется для организации итераций по всем файлам с шагом, равным максимальному числу процессов, которые могут выполняться параллельно.

Внутри находится еще один цикл for , который следит за количеством процессов, запущенных к данному моменту. Этот внутренний цикл также использует команду seq для организации итераций от 0 до максимального числа процессов с шагом, по умолчанию равным 1. В каждой итерации внутренний цикл for извлекает новый файл из списка , вызывая sed, чтобы вывести только требуемое имя файла из списка, сохраненного в начале сценария, и запускает указанную команду с этим файлом в фоновом режиме с применением знака &.

После запуска максимального количества процессов сценарий вызывает команду wait , которая приостанавливает его выполнение до момента, когда завершатся все команды, запущенные в фоновом режиме. После того как wait завершится, вновь начинается процедура запуска процессов для обработки остальных файлов. Она похожа на процедуру выбора лучшей программы сжатия в сценарии bestcompress (сценарий № 34 в главе 4).

Запуск сценария