我的问题是如何更改此代码,以便它只使用4个线程/子进程?
TESTS="a b c d e"
for f in $TESTS; do
t=$[ ( $RANDOM % 5 ) + 1 ]
sleep $t && echo $f $t &
done
wait
答案 0 :(得分:35)
有趣的问题。我尝试使用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之前。
答案 1 :(得分:13)
快速而肮脏的解决方案:在for
循环内的某处插入此行:
while [ $(jobs | wc -l) -ge 4 ] ; do sleep 1 ; done
(假设您还没有在同一个shell中运行其他后台作业)
答案 2 :(得分:8)
我使用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
答案 3 :(得分:5)
您可以使用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
答案 4 :(得分:3)
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
观看介绍视频以了解更多信息:
答案 5 :(得分:0)
这个经过测试的脚本一次运行5个作业,并且会一旦重新启动一个新作业(由于当我们获得SIGCHLD时因为睡眠10.9而被杀死。一个更简单的版本可以使用直接轮询(更改睡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