2016-11-29 2 views
1

Что я хотел бы достичь, это что-то вроде этого:Как выполнить несколько команд с параллелизмом и ограничением ожидания?

#!/bin/sh 
concurrency_limit 3 

#takes 5 min 
(/usr/bin/my-process-1 --args1 && /usr/bin/my-process-2 --args1) & 
#takes 10 min 
(/usr/bin/my-process-1 --args2 && /usr/bin/my-process-2 --args2) & 
#takes 15 min 
(/usr/bin/my-process-1 --args3 && /usr/bin/my-process-2 --args3) & 
#takes 5 min 
(/usr/bin/my-process-1 --args4 && /usr/bin/my-process-2 --args4) & 
#takes 10 min 
(/usr/bin/my-process-1 --args5 && /usr/bin/my-process-2 --args5) & 
#takes 20 min 
(/usr/bin/my-process-1 --args6 && /usr/bin/my-process-2 --args6) & 

wait max_limit 1200 
echo all processes complete 

В целом ожидаемое максимальное время выполнения 20 мин (- + 1мин) и давайте предположим, что у меня есть 3 Процессорные ядра доступны, и я не хочу иметь одновременно работает более 3 процессов.

В начале скрипта началось 3 процесса.

Через 5 мин: 1-й процесс завершен и 4-й процесс начат.

10-й мин: завершены 2-й и 4-й процессы и начат 5-й процесс.

15-й мин. 3-й процесс завершен.

20 мин. 5-й процесс завершен. 6-й процесс убит без дальнейшего ожидания.

Я сделал много исследований в StackOverflow, но я не мог найти подобный случай использования:

How to wait in bash for several subprocesses to finish and return exit code !=0 when any subprocess ends with code !=0?

https://www.codeword.xyz/2015/09/02/three-ways-to-script-processes-in-parallel/

http://www.gnu.org/software/parallel/

Любая помощь или комментарии будут оценены спасибо.

+0

Был ли мой ответ или любые другие проблемы, устраняющие вашу проблему? Если да, пожалуйста, подумайте о том, чтобы принять его как ваш ответ - нажав полый зеленый галочку/галочку рядом с подсчетом голосов. Если нет, скажите, пожалуйста, что не сработало, чтобы я или кто-то еще помог вам дальше. Благодарю. http://meta.stackexchange.com/questions/5234/how-does-accepting-an-answer-work/5235#5235 –

ответ

1

Вы можете сделать это с помощью xargs. Например ниже будет работать функция «Func» 6 раз для аргументов 3,3,4,1,4 и 15 с использованием 3 параллельных процессов, и убить его после 10 секунд:

function func { echo args:$1; sleep $1; echo done; } 
export -f func 

function worktodo { echo -e 3\\n 3\\n 4\\n 1\\n 4\\n 15 | xargs -P 3 -I {} sh -c 'func "[email protected]"' _ {}; } 
export -f worktodo 

timeout 10 sh -c "worktodo" || echo "timeout" 
1

Вот скелет, используя SIGINT для связь между родителем и вашими подпроцессами.

Установить ловушку, которая подсчитывает, сколько процессы заняты, и когда один заканчивается, начать другую:

trap '{ let Trapped++; }' INT # start another child 

Initialize, что сколько вы хотите запустить параллельно:

Trapped=$ATONCE # 3 in your case 

Тогда зациклить и дети по мере необходимости:

while true 
do 
    # Assuming there's more work to do. You need to decide when to terminate 
    do_work & 

    while [ $Trapped -le 0 ] 
     wait   # race condition, interruptible by SIGINT 
     local rc=$? # ... 
    done 
done 

Тогда в do_work вам нужно что-нибудь g like:

call-external-process with parms 

# Deal with problems 
[[ $? -ne 0 ]] && { .... } 

# Now tell parent we're done 
kill -INT $$ 

Это грубая идея. Недостающее - это то, как вы знаете, когда у вас больше нет процессов, и для этого требуется улучшенная обработка ошибок, но, надеюсь, вы получите эту идею. Все три процесса будут выполняться постоянно, новый начинается, когда заканчивается, пока нечего делать.

2

Если я что-то пропустил, думаю GNU Parallel сделает это для вас довольно легко.

Если вы сделаете файл с именем jobs, содержащий:

./my-process-1 --args1 && ./my-process-2 --args1 
./my-process-1 --args2 && ./my-process-2 --args2 
./my-process-1 --args3 && ./my-process-2 --args3 
./my-process-1 --args4 && ./my-process-2 --args4 
./my-process-1 --args5 && ./my-process-2 --args5 
./my-process-1 --args6 && ./my-process-2 --args6 

Тогда вы можете увидеть, что GNU Parallel будет делать с помощью --dry-run следующим образом:

parallel --dry-run -j 3 -k -a jobs 

Выход

./my-process-1 --args1 && ./my-process-2 --args1 
./my-process-1 --args2 && ./my-process-2 --args2 
./my-process-1 --args3 && ./my-process-2 --args3 
./my-process-1 --args4 && ./my-process-2 --args4 
./my-process-1 --args5 && ./my-process-2 --args5 
./my-process-1 --args6 && ./my-process-2 --args6 

Если my-process-1 занимает 3 секунды, а my-process-2 занимает 5 секунд, для полного выполнения требуется 16 секунд, так как первые 3 строки выполняются параллельно, и каждая строка занимает 8 секунд, затем следующие 3 строки выполняются параллельно и принимают еще 8 секунд.

+0

Благодарю вас за ответ. но как насчет общего срока выполнения? – motto

+0

'timeout 120 parallel ...' –