Подтвердить что ты не робот

Как ограничить количество потоков/подпроцессов, используемых в функции в bash

Мой вопрос в том, как изменить этот код, чтобы он использовал только 4 потока/подпроцессы?

TESTS="a b c d e"

for f in $TESTS; do
  t=$[ ( $RANDOM % 5 )  + 1 ]
  sleep $t && echo $f $t &
done
wait
4b9b3361

Ответ 1

Интересный вопрос. Я попытался использовать 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.

Ответ 2

Быстрое и грязное решение: вставьте эту строку где-нибудь внутри цикла for:

while [ $(jobs | wc -l) -ge 4 ] ; do sleep 1 ; done

(предполагается, что у вас еще нет других фоновых заданий в одной оболочке)

Ответ 3

Я нашел другое решение для этого вопроса, используя 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

Ответ 4

Вы можете сделать что-то подобное, используя 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

Ответ 5

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

Смотрите видеоролики, чтобы узнать больше:

http://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Ответ 6

Этот протестированный 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