2009-09-21 10 views
41

मैं अपने कोड का एक सेक्शन अधिक कुशल बनाना चाहता हूं। मैं इसे कई प्रक्रियाओं में फंसे बनाने की सोच रहा हूं और उन्हें केवल एक बार के बजाय 50/100 बार निष्पादित कर रहा हूं।फोर्किंग/बहु-थ्रेडेड प्रक्रियाएं | बैश

उदाहरण के लिए (छद्म):

for line in file; 
do 
foo; 
foo2; 
foo3; 
done 

मैं पाश अनेक बार चलाने के लिए इस चाहते हैं। मुझे पता है कि यह फोर्किंग के साथ किया जा सकता है। क्या ऐसा कुछ दिखता है?

while(x <= 50) 
parent(child pid) 
{ 
    fork child() 
} 
child 
{ 
    do 
    foo; foo2; foo3; 
    done 
    return child_pid() 
} 

या क्या मैं इस गलत तरीके से सोच रहा हूं?

धन्यवाद!

उत्तर

2

मुझे उदाहरण कोशिश

for x in 1 2 3 ; do { echo a $x ; sleep 1 ; echo b $x ; } & done ; sleep 10 

और jobs का उपयोग क्या चल रहा है यह देखने के लिए करते हैं।

26

मुझे किसी भी स्पष्ट fork कॉल में कॉल के बारे में पता नहीं है। आप शायद जो करना चाहते हैं वह & को उस आदेश में जोड़ना है जिसे आप पृष्ठभूमि में चलाने के लिए चाहते हैं।

do_something_with_line() 
{ 
    line=$1 
    foo 
    foo2 
    foo3 
} 

for line in file 
do 
    do_something_with_line $line & 
done 

संपादित: तुम भी कार्यों है कि आप एक bash स्क्रिप्ट के भीतर परिभाषित पर & उपयोग कर सकते हैं एक साथ पृष्ठभूमि प्रक्रियाओं की संख्या पर एक सीमा डाल करने के लिए, आप कुछ इस तरह की कोशिश कर सकते:

for line in file 
do 
    while [`jobs | wc -l` -ge 50 ] 
    do 
    sleep 5 
    done 
    do_something_with_line $line & 
done 
+1

आप miscapitalized गए do_something ... नाम ;-) –

+1

मिल गया - क्या बारे में जब मुझे यकीन है कि मैं केवल हूँ बनाना चाहते एक समय में 50 उदाहरण चल रहे हैं? और - जब उन प्रक्रियाओं में से एक किया जाता है, तो सुनिश्चित करें कि 1 और उत्पन्न हो गया है। – Greg

+0

'जॉब्स' बैश बिल्टिन का उपयोग करें। –

46

डिफ़ॉल्ट रूप से बैश स्क्रिप्ट (गैर-इंटरैक्टिव) में जॉब नियंत्रण अक्षम है ताकि आप आदेश नहीं कर सकें: नौकरी, एफजी, और बीजी।

यहाँ मेरे लिए अच्छी तरह से काम करता है:

#!/bin/sh 

set -m # Enable Job Control 

for i in `seq 30`; do # start 30 jobs in parallel 
    sleep 3 & 
done 

# Wait for all parallel jobs to finish 
while [ 1 ]; do fg 2> /dev/null; [ $? == 1 ] && break; done 

अंतिम पंक्ति "FG" का उपयोग करता अग्रभूमि में एक पृष्ठभूमि काम में लाने के लिए। यह तब तक एक लूप में करता है जब तक कि एफजी 1 ($? == 1) लौटाता है, जो तब होता है जब कोई और पृष्ठभूमि कार्य नहीं होता है।

+16

बैश स्क्रिप्ट में, आप 'प्रतीक्षा' का उपयोग करने में सक्षम हैं, उदाहरण: 'नींद 3 और WAITPID = $ !; $ WAITPID का इंतजार करें, या इस तरह से 'WAITPIDS = "$ WAITPIDS" $!; ...; $ WAITPIDS ' –

+9

या बस" प्रतीक्षा करें "प्रतीक्षा करें। – lethalman

+0

मैं एक समय में 1000 चीजें कैसे करूं?'$ (seq 1 1000)' – chovy

17
जीएनयू साथ

समानांतर आप कर सकते हैं:

cat file | parallel 'foo {}; foo2 {}; foo3 {}' 

यह प्रत्येक सीपीयू कोर पर एक ही काम चलाया जाएगा। 50 को चलाने के लिए कार्य करें:

cat file | parallel -j 50 'foo {}; foo2 {}; foo3 {}' 

घड़ी परिचय वीडियो अधिक जानने के लिए:

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

+2

को ठीक करने के लिए '#!/Bin/bash' का उपयोग करें, नाग-स्क्रीन के अलावा, समानांतर बहुत अच्छा है। –

+1

मैं जोड़ता हूं कि अधिकांश प्रणालियों पर समानांतर पहले से स्थापित है। मेरी ओएस एक्स 10.8.5 मशीन है। मेरे लिए मेरे शेल स्क्रिप्टिंग से कोबवेस को धूलने का समय है और लूप के लिए समानांतर के लिए अपडेट करें ... – labyrinth

+0

यह खोज/प्रतिस्थापन का उपयोग करते समय वास्तविक गड़बड़ हो रहा है जिसमें से बचने वाले पात्र हैं। –

2

आप सभी क्या साझा किया है कि मैं इस एक साथ रखा करने में सक्षम था के आधार पर:

#!/usr/bin/env bash 

VAR1="192.168.1.20 192.168.1.126 192.168.1.36" 

for a in $VAR1; do { ssh -t -t $a -l Administrator "sudo softwareupdate -l"; } & done; 
WAITPIDS="$WAITPIDS "$!;...; wait $WAITPIDS 
echo "Script has finished" 

Exit 1 

यह मैक पर एक ही समय में तीन मशीनों पर सभी अपडेट सूचीबद्ध करता है। बाद में मैंने इसे सभी मशीनों के लिए सॉफ़्टवेयर अपडेट करने के लिए उपयोग किया जब मैं अपने आईपैड्रेस को सीएटी करता हूं।txt

0

यहाँ मेरी धागा नियंत्रण समारोह है:

#!/bin/bash 
# This function just checks jobs in background, don't do more things. 
# if jobs number is lower than MAX, then return to get more jobs; 
# if jobs number is greater or equal to MAX, then wait, until someone finished. 

# Usage: 
# thread_max 8 
# thread_max 0 # wait, until all jobs completed 

thread_max() { 
    local CHECK_INTERVAL="3s" 
    local CUR_THREADS= 
    local MAX= 
    [[ $1 ]] && MAX=$1 || return 127 

    # reset MAX value, 0 is easy to remember 
    [ $MAX -eq 0 ] && { 
     MAX=1 
     DEBUG "waiting for all tasks finish" 
    } 

    while true; do 
     CUR_THREADS=`jobs -p | wc -w` 

     # workaround about jobs bug. If don't execute it explicitily, 
     # CUR_THREADS will stick at 1, even no jobs running anymore. 
     jobs &>/dev/null 

     DEBUG "current thread amount: $CUR_THREADS" 
     if [ $CUR_THREADS -ge $MAX ]; then 
      sleep $CHECK_INTERVAL 
     else 
      return 0 
     fi 
    done 
} 
12

मैं wait का उपयोग कर पसंद नहीं है, क्योंकि यह प्रक्रिया बाहर निकलता है, जो आदर्श नहीं है जब वहाँ के रूप में मैं कर सकते हैं 'पर प्रतीक्षा करने के लिए एक से अधिक प्रक्रिया कर रहे हैं जब तक अवरुद्ध हो जाता है वर्तमान प्रक्रिया पूरी होने तक स्थिति अद्यतन प्राप्त नहीं करें। मैं kill -0 और sleep के संयोजन का उपयोग करना पसंद करता हूं।

प्रतीक्षा करने के लिए pids की एक सरणी को देखते हुए, मैं नीचे दिए गए waitPids() फ़ंक्शन का उपयोग करता हूं ताकि पीआईडी ​​अभी भी समाप्त होने के लिए लंबित हो।

declare -a pids 
waitPids() { 
    while [ ${#pids[@]} -ne 0 ]; do 
     echo "Waiting for pids: ${pids[@]}" 
     local range=$(eval echo {0..$((${#pids[@]}-1))}) 
     local i 
     for i in $range; do 
      if ! kill -0 ${pids[$i]} 2> /dev/null; then 
       echo "Done -- ${pids[$i]}" 
       unset pids[$i] 
      fi 
     done 
     pids=("${pids[@]}") # Expunge nulls created by unset. 
     sleep 1 
    done 
    echo "Done!" 
} 

जब मैं पृष्ठभूमि में एक प्रक्रिया शुरू, मैं अपने पीआईडी ​​तुरंत pids सरणी के लिए उपयोगिता समारोह नीचे इस का उपयोग करके जोड़ें:

addPid() { 
    desc=$1 
    pid=$2 
    echo "$desc -- $pid" 
    pids=(${pids[@]} $pid) 
} 

यहां एक नमूना दिखाता है कि कैसे उपयोग करने के लिए है:

for i in {2..5}; do 
    sleep $i & 
    addPid "Sleep for $i" $! 
done 
waitPids 

और यहाँ कैसे प्रतिक्रिया दिखाई देता है:

Sleep for 2 -- 36271 
Sleep for 3 -- 36272 
Sleep for 4 -- 36273 
Sleep for 5 -- 36274 
Waiting for pids: 36271 36272 36273 36274 
Waiting for pids: 36271 36272 36273 36274 
Waiting for pids: 36271 36272 36273 36274 
Done -- 36271 
Waiting for pids: 36272 36273 36274 
Done -- 36272 
Waiting for pids: 36273 36274 
Done -- 36273 
Waiting for pids: 36274 
Done -- 36274 
Done! 
0

हरिड्स का दृष्टिकोण बहुत अच्छा है, यह एक प्रोसेसर स्लॉट सेटअप चलाने के लिए लचीलापन देता है जहां समग्र प्रक्रियाओं को पूरा करते हुए, नौकरियों को पूरा करने के रूप में सबमिट करने वाली नई नौकरियों के साथ कई प्रक्रियाओं को जारी रखा जा सकता है। यहां ngrid 'नौकरियों' के 'ग्रिड' के लिए एन-स्लॉट प्रोसेसर के लिए हैरिसव के कोड में मेरे मोड हैं (मैं सिमुलेशन मॉडल के ग्रिड के लिए इसका उपयोग करता हूं) एक समय में 8 नौकरियों 3 के लिए परीक्षण आउटपुट द्वारा पीछा किया जाता है, चलने के कुल भाग के साथ , प्रस्तुत, पूरी की और शेष

#!/bin/bash 
######################################################################## 
# see haridsv on forking-multi-threaded-processes-bash 
# loop over grid, submitting jobs in the background. 
# As jobs complete new ones are set going to keep the number running 
# up to n as much as possible, until it tapers off at the end. 
# 
# 8 jobs 
ngrid=8 
# 3 at a time 
n=3 
# running counts 
running=0 
completed=0 
# previous values 
prunning=0 
pcompleted=0 
# 
######################################################################## 
# process monitoring functions 
# 
declare -a pids 
# 
function checkPids() { 
echo ${#pids[@]} 
if [ ${#pids[@]} -ne 0 ] 
then 
    echo "Checking for pids: ${pids[@]}" 
    local range=$(eval echo {0..$((${#pids[@]}-1))}) 
    local i 
    for i in $range; do 
     if ! kill -0 ${pids[$i]} 2> /dev/null; then 
      echo "Done -- ${pids[$i]}" 
      unset pids[$i] 
      completed=$(expr $completed + 1) 
     fi 
    done 
    pids=("${pids[@]}") # Expunge nulls created by unset. 
    running=$((${#pids[@]})) 
    echo "#PIDS :"$running 
fi 
} 
# 
function addPid() { 
    desc=$1 
    pid=$2 
    echo " ${desc} - "$pid 
    pids=(${pids[@]} $pid) 
} 
######################################################################## 
# 
# Loop and report when job changes happen, 
# keep going until all are completed. 
# 
idx=0 
while [ $completed -lt ${ngrid} ] 
do 
# 
    if [ $running -lt $n ] && [ $idx -lt ${ngrid} ] 
    then 
#################################################################### 
# 
# submit a new process if less than n 
# are running and we haven't finished... 
# 
# get desc for process 
# 
     name="job_"${idx} 
# background execution 
     sleep 3 & 
     addPid $name $! 
     idx=$(expr $idx + 1) 
# 
#################################################################### 
# 
    fi 
# 
    checkPids 
# if something changes... 
    if [ ${running} -gt ${prunning} ] || \ 
     [ ${completed} -gt ${pcompleted} ] 
    then 
     remain=$(expr $ngrid - $completed) 
     echo " Running: "${running}" Submitted: "${idx}\ 
       " Completed: "$completed" Remaining: "$remain 
    fi 
# save counts to prev values 
    prunning=${running} 
    pcompleted=${completed} 
# 
    sleep 1 
# 
done 
# 
######################################################################## 

टेस्ट उत्पादन:

job_0 - 75257 
1 
Checking for pids: 75257 
#PIDS :1 
Running: 1 Submitted: 1 Completed: 0 Remaining: 8 
job_1 - 75262 
2 
Checking for pids: 75257 75262 
#PIDS :2 
Running: 2 Submitted: 2 Completed: 0 Remaining: 8 
job_2 - 75267 
3 
Checking for pids: 75257 75262 75267 
#PIDS :3 
Running: 3 Submitted: 3 Completed: 0 Remaining: 8 
3 
Checking for pids: 75257 75262 75267 
Done -- 75257 
#PIDS :2 
Running: 2 Submitted: 3 Completed: 1 Remaining: 7 
job_3 - 75277 
3 
Checking for pids: 75262 75267 75277 
Done -- 75262 
#PIDS :2 
Running: 2 Submitted: 4 Completed: 2 Remaining: 6 
job_4 - 75283 
3 
Checking for pids: 75267 75277 75283 
Done -- 75267 
#PIDS :2 
Running: 2 Submitted: 5 Completed: 3 Remaining: 5 
job_5 - 75289 
3 
Checking for pids: 75277 75283 75289 
#PIDS :3 
Running: 3 Submitted: 6 Completed: 3 Remaining: 5 
3 
Checking for pids: 75277 75283 75289 
Done -- 75277 
#PIDS :2 
Running: 2 Submitted: 6 Completed: 4 Remaining: 4 
job_6 - 75298 
3 
Checking for pids: 75283 75289 75298 
Done -- 75283 
#PIDS :2 
Running: 2 Submitted: 7 Completed: 5 Remaining: 3 
job_7 - 75304 
3 
Checking for pids: 75289 75298 75304 
Done -- 75289 
#PIDS :2 
Running: 2 Submitted: 8 Completed: 6 Remaining: 2 
2 
Checking for pids: 75298 75304 
#PIDS :2 
2 
Checking for pids: 75298 75304 
Done -- 75298 
#PIDS :1 
Running: 1 Submitted: 8 Completed: 7 Remaining: 1 
1 
Checking for pids: 75304 
Done -- 75304 
#PIDS :0 
Running: 0 Submitted: 8 Completed: 8 Remaining: 0 
संबंधित मुद्दे