Мой вопрос в том, как изменить этот код, чтобы он использовал только 4 потока/подпроцессы?
TESTS="a b c d e"
for f in $TESTS; do
t=$[ ( $RANDOM % 5 ) + 1 ]
sleep $t && echo $f $t &
done
wait
Мой вопрос в том, как изменить этот код, чтобы он использовал только 4 потока/подпроцессы?
TESTS="a b c d e"
for f in $TESTS; do
t=$[ ( $RANDOM % 5 ) + 1 ]
sleep $t && echo $f $t &
done
wait
Интересный вопрос. Я попытался использовать xargs для этого, и я нашел способ.
Попробуйте следующее:
seq 10 | xargs -i --max-procs=4 bash -c "echo start {}; sleep 3; echo done {}"
--max-procs=4
гарантирует, что одновременно выполняется не более четырех подпроцессов.
Результат будет выглядеть так:
start 2
start 3
start 1
start 4
done 2
done 3
done 1
done 4
start 6
start 5
start 7
start 8
done 6
done 5
start 9
done 8
done 7
start 10
done 9
done 10
Обратите внимание, что порядок выполнения может не соответствовать командам в том порядке, в котором вы их отправляете. Как вы можете видеть, 2 началось до 1.
Быстрое и грязное решение: вставьте эту строку где-нибудь внутри цикла for
:
while [ $(jobs | wc -l) -ge 4 ] ; do sleep 1 ; done
(предполагается, что у вас еще нет других фоновых заданий в одной оболочке)
Я нашел другое решение для этого вопроса, используя parallel
(часть пакета moreutils
.)
parallel -j 4 -i bash -c "echo start {}; sleep 2; echo done {};" -- $(seq 10)
-j 4
означает -j maxjobs
-i
использует параметры как {}
--
ограничивает ваши аргументы
Вывод этой команды будет:
start 3
start 4
start 1
start 2
done 4
done 2
done 3
done 1
start 5
start 6
start 7
start 8
done 5
done 6
start 9
done 7
start 10
done 8
done 9
done 10
Вы можете сделать что-то подобное, используя jobs
builtin:
for f in $TESTS; do
running=($(jobs -rp))
while [ ${#running[@]} -ge 4 ] ; do
sleep 1 # this is not optimal, but you can't use wait here
running=($(jobs -rp))
done
t=$[ ( $RANDOM % 5 ) + 1 ]
sleep $t && echo $f $t &
done
wait
GNU Parallel предназначен для таких задач:
TESTS="a b c d e"
for f in $TESTS; do
t=$[ ( $RANDOM % 5 ) + 1 ]
sem -j4 sleep $t && echo $f $t
done
sem --wait
Смотрите видеоролики, чтобы узнать больше:
Этот протестированный script запускает по 5 заданий одновременно и перезапустит новое задание, как только это произойдет (из-за убийства сна 10.9, когда мы получаем SIGCHLD. Простая версия этого может использовать прямой опрос ( измените сон 10.9, чтобы спать 1 и избавиться от ловушки).
#!/usr/bin/bash
set -o monitor
trap "pkill -P $$ -f 'sleep 10\.9' >&/dev/null" SIGCHLD
totaljobs=15
numjobs=5
worktime=10
curjobs=0
declare -A pidlist
dojob()
{
slot=$1
time=$(echo "$RANDOM * 10 / 32768" | bc -l)
echo Starting job $slot with args $time
sleep $time &
pidlist[$slot]=`jobs -p %%`
curjobs=$(($curjobs + 1))
totaljobs=$(($totaljobs - 1))
}
# start
while [ $curjobs -lt $numjobs -a $totaljobs -gt 0 ]
do
dojob $curjobs
done
# Poll for jobs to die, restarting while we have them
while [ $totaljobs -gt 0 ]
do
for ((i=0;$i < $curjobs;i++))
do
if ! kill -0 ${pidlist[$i]} >&/dev/null
then
dojob $i
break
fi
done
sleep 10.9 >&/dev/null
done
wait