У меня проблема со сценариями оболочки, когда у меня есть каталог, полный входных файлов (каждый файл содержит много входных строк), и мне нужно обрабатывать их индивидуально, перенаправляя каждый из их выходных данных в уникальный файл (иначе, file_1.input needs). быть захваченным в file_1.output и т. д.).
Предварительно , я бы просто перебирал каждый файл в каталоге и выполнял свою команду, выполняя какую-то технику таймера / подсчета, чтобы не перегружать процессоры (предполагая, что каждый процесс имел постоянное время выполнения). Однако я знаю, что это не всегда так, поэтому использование «параллельного» решения кажется лучшим способом получить многопоточность сценария оболочки без написания специального кода.
Хотя я подумал о некоторых способах параллельного запуска для обработки каждого из этих файлов (и позволяющего мне эффективно управлять своими ядрами), все они кажутся хакерскими. У меня есть то, что я считаю довольно простым вариантом использования, поэтому я предпочел бы сохранить его как можно более чистым (и ничто в параллельных примерах, кажется, не выпрыгивает из моей проблемы).
Любая помощь будет оценена!
Пример входного каталога:
> ls -l input_files/
total 13355
location1.txt
location2.txt
location3.txt
location4.txt
location5.txt
Автор сценария:
> cat proces_script.sh
#!/bin/sh
customScript -c 33 -I -file [inputFile] -a -v 55 > [outputFile]
Обновление : после прочтения ответа Оле ниже, я смог собрать недостающие фрагменты для моей собственной параллельной реализации. Хотя его ответ хорош, вот мое дополнительное исследование и заметки, которые я сделал:
Вместо того чтобы запускать весь процесс, я решил начать с команды проверки концепции, чтобы доказать его решение в моей среде. Смотрите мои две разные реализации (и заметки):
find /home/me/input_files -type f -name *.txt | parallel cat /home/me/input_files/{} '>' /home/me/output_files/{.}.out
Использует find (не ls, это может вызвать проблемы), чтобы найти все применимые файлы в моем каталоге входных файлов, а затем перенаправляет их содержимое в отдельный каталог и файл. Моей проблемой сверху было чтение и перенаправление (фактический скрипт был прост), поэтому замена скрипта на cat была хорошим доказательством концепции.
parallel cat '>' /home/me/output_files/{.}.out ::: /home/me/input_files/*
Это второе решение использует парадигму входной переменной параллельного интерфейса для чтения файлов, однако для новичка это было гораздо более запутанным. Для меня использование find и pipe отвечает моим потребностям.
Стандартный способ сделать это - настроить очередь и породить любое количество работников, которые знают, как извлечь что-то из очереди и обработать. Вы можете использовать fifo (он же именованный канал) для связи между этими процессами.
Ниже приведен наивный пример для демонстрации концепции.
Простой скрипт очереди:
И рабочий:
process_file
может быть определен где-то в вашем работнике, и он может делать все, что вам нужно.Когда у вас есть эти две части, вы можете иметь простой монитор, который запускает процесс очереди и любое количество рабочих процессов.
Скрипт монитора:
Там у вас есть это. Если вы действительно делаете это, лучше настроить fifo на мониторе и передать путь как к очереди, так и к рабочим, чтобы они не были связаны и не привязывались к определенному месту для fifo. Я специально настроил это в ответе, чтобы было ясно, что вы используете, когда читаете это.
источник
monitor_workers
это какprocess_file
... это функция, которая делает все, что вы хотите. Насчет монитора - ты был прав; он должен сохранить pids своих работников (чтобы он мог послать сигнал уничтожения), и счетчик должен быть увеличен при запуске работника. Я отредактировал ответ, чтобы включить это.parallel
. Я думаю, что это ваша идея, полностью реализована.Другой пример:
Я нашел другие примеры излишне сложными, когда в большинстве случаев вы, возможно, искали вышеуказанное.
источник
Общедоступным инструментом, который может выполнять распараллеливание, является make. GNU make и несколько других имеют
-j
возможность выполнять параллельные сборки.Запустите
make
как это (я предполагаю, что ваши имена файлов не содержат никаких специальных символов,make
это не хорошо):источник
Это выполнить ту же команду для большого набора файлов в текущем каталоге:
Это запускает
customScript
каждыйtxt
файл, помещая вывод вouttxt
файлы. Измените как вам нужно. Ключом к тому, чтобы заставить это работать, является обработка сигнала с использованием SIGUSR1, чтобы дочерний процесс мог сообщить родительскому процессу, что это сделано. Использование SIGCHLD не будет работать, так как большинство операторов в сценарии будут генерировать сигналы SIGCHLD для сценария оболочки. Я попытался это заменить вашу команду наsleep 1
, программа использовала 0,28 с процессора пользователя и 0,14 с процессора системы; это было только около 400 файлов.источник
wait
что «достаточно умный»; но он вернется после полученияSIGUSR1
сигнала. Дочерний / рабочий отправляетSIGUSR1
родительскому элементу a , который перехватывается (trap
), и уменьшает$worker
(trap
предложение) и ненормально возвращается изwait
, позволяяif [ $worker -lt $num_workers ]
выполнить предложение.Или просто используйте
xargs -P
, не нужно устанавливать дополнительное программное обеспечение:Немного объяснения вариантов:
-I'XXX'
устанавливает строку, которая будет заменена в шаблоне команды именем файла-P4
будет запускать 4 процесса параллельно-n1
поместит только один файл за исполнение, хотя найдены два XXX-print0
и-0
работать вместе, позволяя вам иметь специальные символы (например, пробелы) в именах файловисточник