Как ограничить количество потоков / подпроцессов, используемых в функции в bash - PullRequest
21 голосов
/ 28 июня 2011

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

TESTS="a b c d e"

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

Ответы [ 6 ]

35 голосов
/ 29 июня 2011

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

13 голосов
/ 29 июня 2011

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

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

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

8 голосов
/ 01 июля 2011

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

Вы можете сделать что-то подобное с помощью встроенной функции jobs:

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
3 голосов
/ 05 января 2012

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

0 голосов
/ 29 июня 2011

Этот проверенный скрипт запускает 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...