2011-06-28 82 views
21

我的問題是如何更改此代碼,以便它將只使用4個線程/子進程?如何限制在bash中使用的線程/子進程的數量

TESTS="a b c d e" 

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

這些都不是線程,但子流程。 –

+2

您能否考慮接受答案並將「線索」更改爲您的問題中的「子流程」?使用錯誤的詞語會使網站難以找到! ;-) – Peque

回答

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 
0

此測試腳本運行在一個時間晚五組的工作,並會盡快爲它(因重啓新工作睡眠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 
32

有趣的問題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.前開始

13

快速和骯髒的解決方案:某處插入此行您for循環內:

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

(假設你還沒有擁有在同一個shell中運行其他後臺作業)

+4

這可能比'jobs -r'更有效率 - 沒有它,你會計算bash告訴你哪些作業已經完成的行數。 – Mat

+0

這個解決方案非常棒。我只是在正確的地方插入線,並繁榮! 我喜歡,我根本不需要改變我的腳本結構 –

7

我已經發現了使用moreutils包的parallel(部分這一問題的另一解決方案。)

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