KSH: ограничение количества потоков, которые могут выполняться одновременно

У меня есть скрипт, который зацикливается, и каждая итерация вызывает поток, который работает в фоновом режиме, как показано ниже.

xn_run_process.sh

...
for each in `ls ${INPUT_DIR}/MDX*.txt`
do
      java -Xms256m -Xmx1024m -cp ${CLASSPATH} com.wf.xn.etcc.Main -config=${CONFIG_FILE}
      ...
      for SCALE_PDF in `ls ${PROCESS_DIR}/*.pdf`
      do
          OUTPUT_AFP=${OUTPUT_DIR}/`basename ${SCALE_PDF}`
          OUTPUT_AFP=`print ${OUTPUT_AFP} | sed s/pdf/afp/g`
          ${PROJ_DIR}/myscript.sh -i ${SCALE_PDF} -o ${OUTPUT_AFP} &
          sleep 30
      done
done

Когда я сделал это, я только подумал, что одновременно будут выполняться только 5 потоков из myscript.sh, однако все меняется, и этот список выполняет 30 потоков, каждый из которых выполняет довольно тяжелый процесс. Как ограничить количество одновременных процессов до 5?


person Thang Pham    schedule 01.12.2011    source источник


Ответы (3)


Хотя это возможно в сценариях чистой оболочки, самым простым подходом было бы использование инструмента распараллеливания, такого как GNU parallel или GNU make. Пример мейкфайла:

SOURCES = ${SOME_LIST}
STAMPS = $(SOME_LIST:=.did-run-stamp)

all : $(STAMPS)

%.did-run-stamp : %
    /full/path/myscript.sh -f $<

а затем вызов make as make -j 5.

person thiton    schedule 01.12.2011
comment
привет, вы вызываете make -j 5 внутри скрипта или в оболочке? и разве вы не должны поставить target вместо make? - person Thang Pham; 01.12.2011
comment
не могли бы вы также немного рассказать о did-run-stamp, пожалуйста? - person Thang Pham; 01.12.2011
comment
Внутри оболочки, в каталоге, где показан файл, находится файл Makefile. Make по умолчанию использует первую цель (all по соглашению), а did-run-stamp — это просто фиктивное имя файла, которое еще не существует и действует как цель для make. Если вы будете использовать исходные имена файлов, make просто проверит наличие всех файлов и успешно завершится без каких-либо действий. - person thiton; 01.12.2011
comment
Я обновил некоторые коды, и еще два вопроса, не могли бы вы показать мне? Большое спасибо - person Thang Pham; 01.12.2011
comment
@HarryPham: Извините, но я чувствую, что слишком далеко ухожу от советов к написанию кода. Мой пост (конечно, как и любой другой) открыт для редактирования, если найдется кто-то более мотивированный. Это должно быть довольно прямолинейно с make. Если вы действительно не можете продвигаться вперед, найдите хороший учебник make; info make хорошее начало. - person thiton; 01.12.2011
comment
Чем больше я смотрю на этот make, его цель больше состоит в компиляции программы, а не в выполнении другого скрипта во время выполнения. Спасибо хоть. - person Thang Pham; 01.12.2011
comment
@HarryPham: Да, первоначальная цель make немного отличается, но управление запуском недалеко от управления компиляцией. GNU parallel больше ориентирован на параллельное выполнение. - person thiton; 01.12.2011

Используйте GNU Parallel (настройте -j по своему усмотрению. Удалите его, если хотите количество процессоров):

for each in `ls ${INPUT_DIR}/MDX*.txt`
do
      java -Xms256m -Xmx1024m -cp ${CLASSPATH} com.wf.xn.etcc.Main -config=${CONFIG_FILE}
      ...
      for SCALE_PDF in `ls ${PROCESS_DIR}/*.pdf`
      do
          OUTPUT_AFP=${OUTPUT_DIR}/`basename ${SCALE_PDF}`
          OUTPUT_AFP=`print ${OUTPUT_AFP} | sed s/pdf/afp/g`
          sem --id myid -j 5 ${PROJ_DIR}/myscript.sh -i ${SCALE_PDF} -o ${OUTPUT_AFP}
      done
done
sem --wait --id myid

sem является частью GNU Parallel.

Это будет поддерживать выполнение 5 заданий до тех пор, пока не останется только 5 заданий. Затем он позволит вашей Java работать, пока завершатся последние 5. sem --wait будет ждать, пока не будут завершены последние 5.

В качестве альтернативы:

for each ...
   java ...
   ...
   ls ${PROCESS_DIR}/*.pdf |
   parallel -j 5 ${PROJ_DIR}/myscript.sh -i {} -o ${OUTPUT_DIR}/{/.}.afp
done

Это будет запускать 5 заданий параллельно и запускать java только после завершения всех заданий.

В качестве альтернативы вы можете использовать трюк с очередью, описанный на странице руководства GNU Parallel: https://www.gnu.org/software/parallel/man.html#example__gnu_parallel_as_queue_system_batch_manager

echo >jobqueue; tail -f jobqueue | parallel -j5 &
for each ...
   ...
   ls ${PROCESS_DIR}/*.pdf |
   parallel echo ${PROJ_DIR}/myscript.sh -i {} -o ${OUTPUT_DIR}/{/.}.afp >> jobqueue
done
echo killall -TERM parallel >> jobqueue
wait

Это запустит java, а затем добавит задания для запуска в очередь. После добавления заданий java запустится сразу. За все время из очереди будет выполняться 5 заданий, пока очередь не опустеет.

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

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

Чтобы узнать больше, посмотрите вступительные видеоролики: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 и пройдитесь по учебнику (man parallel_tutorial). Вы управляете строкой с любовью вас за это.

person Ole Tange    schedule 07.12.2011

Если у вас ksh93, проверьте, доступен ли JOBMAX:

ДЖОБМАКС

This variable defines the maximum number running background
jobs that can run at a time. When this limit is reached, the
shell will wait for a job to complete before staring a new job.
person Dimitre Radoulov    schedule 08.12.2011