Четыре задачи параллельно … как это сделать?

У меня есть куча изображений PNG в каталоге. У меня есть приложение pngout, которое я запускаю для сжатия этих изображений. Это приложение вызывается сценарием, который я сделал. Проблема в том, что этот скрипт делает по одному, что-то вроде этого:

FILES=(./*.png) for f in "${FILES[@]}" do echo "Processing $f file..." # take action on each file. $f store current file name ./pngout -s0 $f R${f/\.\//} done 

Обработка только одного файла за раз, занимает много времени. После запуска этого приложения я вижу, что процессор составляет всего 10%. Поэтому я обнаружил, что могу разделить эти файлы на 4 партии, поместить каждую партию в каталог и запустить 4 из четырех окон терминала, четыре процесса, поэтому у меня есть четыре экземпляра моего сценария, в то же время, обработка этих изображений и работа занимает 1/4 времени.

Вторая проблема заключается в том, что я потерял время, разделяя изображения и партии и копируя сценарий в четыре каталога, открывая 4 окна терминала, bla bla …

Как это сделать с одним сценарием, без необходимости чего-либо делить?

Я имею в виду две вещи: сначала, как я из сценария bash, запускаю процесс на задний план? (просто добавьте и до конца?) Во-вторых: как мне прекратить отправку задач на задний план после отправки четвертых задач и поставить сценарий в ожидании окончания задач? Я имею в виду, просто отправляя новую задачу на задний план, когда заканчивается одна задача, одновременно сохраняя 4 задачи? если я не сделаю этого, цикл запустит zillions задач на задний план и процессор засорится.

Если у вас есть копия xargs которая поддерживает параллельное выполнение с -P , вы можете просто сделать

 printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{} 

Для других идей Wiki Wooledge Bash содержит раздел в статье «Управление процессом», в котором описывается, что именно вы хотите.

В дополнение к уже предложенным решениям вы можете создать make-файл, который описывает, как сделать сжатый файл несжатым, и использовать make -j 4 для одновременного запуска 4 заданий. Проблема в том, что вам нужно будет указывать сжатые и несжатые файлы по-разному или хранить их в разных каталогах, иначе написать разумное правило make будет невозможно.

Если у вас установлен GNU Parallel http://www.gnu.org/software/parallel/, вы можете сделать это:

 parallel ./pngout -s0 {} R{} ::: *.png 

Вы можете установить GNU Parallel, просто:

 wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel chmod 755 parallel cp parallel sem 

Смотрите видеоролики для GNU. Параллельно узнайте больше: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Чтобы ответить на два вопроса:

  • да, добавление & в конце строки даст вам команду для запуска фонового процесса.
  • используя команду wait , вы можете попросить оболочку дождаться завершения всех процессов в фоновом режиме, прежде чем продолжить.

Здесь скрипт изменен так, что j используется для отслеживания количества фоновых процессов. Когда будет достигнуто значение NB_CONCURRENT_PROCESSES , сценарий сбрасывает j на 0 и ждет завершения всех фоновых процессов до возобновления его выполнения.

 files=(./*.png) nb_concurrent_processes=4 j=0 for f in "${files[@]}" do echo "Processing $f file..." # take action on each file. $f store current file name ./pngout -s0 "$f" R"${f/\.\//}" & ((++j == nb_concurrent_processes)) && { j=0; wait; } done