2009-09-21 15 views
41

私のコードのセクションをより効率的にしたいと考えています。私はそれを複数のプロセスに分岐させ、一度ではなく一度に50/100回実行させることを考えています。例えばフォーク/マルチスレッドプロセス| Bash

(擬似):

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

私はbashの明示的なforkコールについて知らない。おそらく実行したいのは、バックグラウンドで実行するコマンドに& を追加することです。また、あなたはbashスクリプト内で定義関数に&を使用することができます。

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

for line in file 
do 
    do_something_with_line $line & 
done 

EDIT:同時バックグラウンド・プロセスの数に制限を置くために、あなたはこのような何かを試みることができる:

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

あなたはdo_somethingをmiscapitalizedきた...名前;-) –

+1

はそれを手に入れた - 私は確信して私は午前したいときについて一度に50のインスタンスを実行していますか?そして、それらのプロセスの1つが完了したら、さらに1つが生成されていることを確認してください。 – Greg

+0

'ジョブ' bash組み込み関数を使います。 –

46

bashスクリプト(非インタラクティブ)では、デフォルトでJOB CONTROLが無効になっているため、job、fg、およびbgというコマンドは実行できません。ここで

は私のためにうまく機能するものである:

#!/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」を使用しています。これは、fgが1($?== 1)を返すまでこれをループで行います。これは、もはやバックグラウンドジョブがなくなったときに行います。 GNUで

+16

bashスクリプトでは、 'wait 'を使うことができます。例えば' sleep 3&WAITPID = $ !; $ WAITPID'を待つか、またはこの方法でピッドを連結します。WAITPIDS = "$ WAITPIDS" $!; ...; $ WAITPIDS'を待ちます –

+9

または単に「待つ」。 – lethalman

+0

一度に50点、1000点をどうすればいいですか?'$(seq 1 1000)'のループで – chovy

17

を行うことができますパラレル:

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

これは、各CPUコアに1つのジョブを実行します。 50を実行するために実行します。

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

ウォッチをイントロ動画の詳細を学ぶために:あなたは、すべて私が一緒にこれを置くことができた共有かに

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

+2

nag-screenを除いて、並列はとてもかっこいいです。 –

+1

私はパラレルが既にほとんどのシステムにインストールされていると付け加えます。私のOS X 10.8.5マシンはそれを持っています。それは私のシェルスクリプトからcobwebsをほこりを落として、私のforループをパラレルに更新する時です... – 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 

これは、一度に3台のマシン上のMac上のすべてのアップデートを一覧表示します。後で、私は自分のipaddressをCATするときに、すべてのマシンのソフトウェアアップデートを実行するために使用しました。TXT

0

ここに私のスレッド制御機能です:「、それはプロセスが終了するまでブロックされますので、私はwaitを使用して好きではない

#!/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

複数のプロセスは、私ができるように待機する必要がある場合に理想的ではないとします現在のプロセスが完了するまでステータス更新を取得しないでください。私はこれにkill -0sleepの組み合わせを使うのが好きです。

pidsの配列が与えられている場合、私は以下のwaitPids()関数を使用して、どのpidがまだ終了していないかを継続的にフィードバックします。

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配列にすぐにそのPIDを追加します。ここでは

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

haridsvのアプローチは素晴らしいです。プロセッサスロットの設定を柔軟に実行できるため、ジョブの完了時に新しいジョブが実行されて多数のプロセスが実行され、全体的な負荷が高くなります。ここで、haridsvのnスロットプロセッサ用のnスロットプロセッサ用のコードを紹介します(私はシミュレーションモデルのグリッド用にグリッドを使用しています)。実行時合計を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