bash

2011-06-28 12 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 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 
0

यह परीक्षण किया स्क्रिप्ट एक समय में 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 
32

दिलचस्प questi पर। मैंने इसके लिए xargs का उपयोग करने की कोशिश की और मुझे एक रास्ता मिला।

इस प्रयास करें:

seq 10 | xargs -i --max-procs=4 bash -c "echo start {}; sleep 3; echo done {}" 

--max-procs=4 यह सुनिश्चित करेंगे कि कोई चार से अधिक subprocesses एक समय में चल रहे हैं।

उत्पादन इस तरह दिखेगा:

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 

(मान लिया गया है आप पहले से ही नहीं है अन्य पृष्ठभूमि एक ही खोल में चल रहे नौकरी)

+4

यह 'जॉब्स-आर' के साथ बहुत अधिक कुशल हो सकता है - इसके बिना, आप उन लाइनों की गिनती करेंगे जहां बैश आपको बताता है कि कौन सी नौकरियां पहले ही हो चुकी हैं। – Mat

+0

यह समाधान बहुत अच्छा है। मैं सिर्फ सही जगह पर लाइन डालता हूं और उछालता हूं! मुझे पसंद आया कि मुझे अपनी स्क्रिप्ट संरचना को बिल्कुल बदलने की ज़रूरत नहीं है –

7

मैं इस सवाल parallel (moreutils पैकेज के भाग के प्रयोग करने के लिए एक और समाधान मिल गया है।)

parallel -j 4 -i bash -c "echo start {}; sleep 2; echo done {};" -- $(seq 10) 

-j 4 के लिए -j maxjobs

-i खड़ा के रूप में {}

-- delimits अपने तर्क

पैरामीटर का उपयोग करता

इस आदेश के उत्पादन में हो जाएगा:

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

जीएनयू समानांतर इस तरह लिए बनाया गया है कार्यों का:

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