Последовательный: for i in {1..1000}; do do_something $i; done
- слишком медленный
Параллель: for i in {1..1000}; do do_something $i& done
- слишком много загрузки
Как к командам выполнения параллельно, но не больше, чем, например, 20 экземпляров в момент?
Теперь обычно использование взлома как for i in {1..1000}; do do_something $i& sleep 5; done
, но это не хорошее решение.
Обновление 2: Преобразованный принятый ответ в сценарий: http://vi-server.org/vi/parallel
#!/bin/bash
NUM=$1; shift
if [ -z "$NUM" ]; then
echo "Usage: parallel <number_of_tasks> command"
echo " Sets environment variable i from 1 to number_of_tasks"
echo " Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
exit 1
fi
export CMD="$@";
true ${MAKEOPTS:="-j20"}
cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(shell echo {1..$NUM})
all: \${jobs}
\${jobs}:
i=\$@ sh -c "\$\$CMD"
EOF
Обратите внимание, что необходимо заменить 8 пробелов 2 вкладками прежде чем "я =", чтобы заставить его работать.
Параллель GNU сделана для этого.
seq 1 1000 | parallel -j20 do_something
Это может даже выполнить задания на удаленных компьютерах. Вот пример для перекодирования MP3 к OGG, использующему server2 и локальный компьютер, выполняющий 1 задание на ядро процессора:
parallel --trc {.}.ogg -j+0 -S server2,: \
'mpg321 -w - {} | oggenc -q0 - -o {.}.ogg' ::: *.mp3
Посмотрите вводное видео к Параллели GNU здесь:
Не решение для удара, но необходимо использовать Make-файл, возможно с -l
не превысить некоторую максимальную нагрузку.
NJOBS=1000
.PHONY = jobs
jobs = $(shell echo {1..$(NJOBS)})
all: $(jobs)
$(jobs):
do_something $@
Затем для запуска 20 заданий за один раз делают
$ make -j20
или запустить как можно больше заданий, не превышая загрузку 5
$ make -j -l5
регистрация сценария в вопросе с форматированием:
#!/bin/bash
NUM=$1; shift
if [ -z "$NUM" ]; then
echo "Usage: parallel <number_of_tasks> command"
echo " Sets environment variable i from 1 to number_of_tasks"
echo " Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
exit 1
fi
export CMD="$@";
true ${MAKEOPTS:="-j20"}
cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(shell echo {1..$NUM})
all: \${jobs}
\${jobs}:
i=\$@ sh -c "\$\$CMD"
EOF
Обратите внимание, что необходимо заменить 8 пробелов 2 вкладками прежде чем "я =".
Вы могли использовать ps
для подсчета, сколько процессов у Вас есть выполнение, и каждый раз, когда это опускается ниже определенного порога, Вы запускаете другой процесс.
Псевдо код:
i = 1
MAX_PROCESSES=20
NUM_TASKS=1000
do
get num_processes using ps
if num_processes < MAX_PROCESSES
start process $i
$i = $i + 1
endif
sleep 1 # add this to prevent thrashing with ps
until $i > NUM_TASKS