順次:for i in {1..1000}; do do_something $i; done
-遅すぎる
パラレル:for i in {1..1000}; do do_something $i& done
-負荷が高すぎます
コマンドを並行して実行する方法、ただし、たとえば、瞬間あたり20インスタンス以下
現在は通常for i in {1..1000}; do do_something $i& sleep 5; done
のようなハックを使用していますが、これは良い解決策ではありません。
アップデート2:承認された回答をスクリプトに変換しました: http://vi-server.org/vi/parallel
#!/bin/bash
NUM=$1; shift
if [ -z "$NUM" ]; then
echo "Usage: parallel <number_of_tasks> command"
echo " Sets environment variable i from 1 to number_of_tasks"
echo " Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
exit 1
fi
export CMD="$@";
true ${MAKEOPTS:="-j20"}
cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(Shell echo {1..$NUM})
all: \${jobs}
\${jobs}:
i=\$@ sh -c "\$\$CMD"
EOF
機能させるには、「i =」の前に8つのスペースを2つのタブで置き換える必要があることに注意してください。
GNU Parallel はこのために作られています。
seq 1 1000 | parallel -j20 do_something
リモートコンピューターでジョブを実行することもできます。 CPUコアごとに1つのジョブを実行するserver2およびローカルコンピューターを使用してMP3をOGGに再エンコードする例を次に示します。
parallel --trc {.}.ogg -j+0 -S server2,: \
'mpg321 -w - {} | oggenc -q0 - -o {.}.ogg' ::: *.mp3
GNU Parallelの紹介ビデオを見る:
Bashソリューションではありませんが、Makefileを使用する必要があります。最大負荷を超えないようにするには、-l
を使用する必要があります。
NJOBS=1000
.PHONY = jobs
jobs = $(Shell echo {1..$(NJOBS)})
all: $(jobs)
$(jobs):
do_something $@
次に、一度に20個のジョブを開始するには
$ make -j20
または、負荷5を超えずに、できるだけ多くのジョブを開始する
$ make -j -l5
質問のスクリプトをフォーマットして投稿します:
#!/bin/bash
NUM=$1; shift
if [ -z "$NUM" ]; then
echo "Usage: parallel <number_of_tasks> command"
echo " Sets environment variable i from 1 to number_of_tasks"
echo " Defaults to 20 processes at a time, use like \"MAKEOPTS='-j5' parallel ...\" to override."
echo "Example: parallel 100 'echo \$i; sleep \`echo \$RANDOM/6553 | bc -l\`'"
exit 1
fi
export CMD="$@";
true ${MAKEOPTS:="-j20"}
cat << EOF | make -f - -s $MAKEOPTS
PHONY=jobs
jobs=\$(Shell echo {1..$NUM})
all: \${jobs}
\${jobs}:
i=\$@ sh -c "\$\$CMD"
EOF
「i =」の前に、8つのスペースを2つのタブで置き換える必要があることに注意してください。
簡単なアイデア:
20を法とするiをチェックし、do_somethingの前に待機シェルコマンドを実行します。
for i in {1..1000}; do
(echo $i ; sleep `expr $RANDOM % 5` ) &
while [ `jobs | wc -l` -ge 20 ] ; do
sleep 1
done
done
ps
を使用して、実行しているプロセスの数を数えることができます。これが特定のしきい値を下回ると、別のプロセスを開始できます。
疑似コード:
i = 1
MAX_PROCESSES=20
NUM_TASKS=1000
do
get num_processes using ps
if num_processes < MAX_PROCESSES
start process $i
$i = $i + 1
endif
sleep 1 # add this to prevent thrashing with ps
until $i > NUM_TASKS
このようにできます。
threads=20
tempfifo=$PMS_HOME/$$.fifo
trap "exec 1000>&-;exec 1000<&-;exit 0" 2
mkfifo $tempfifo
exec 1000<>$tempfifo
rm -rf $tempfifo
for ((i=1; i<=$threads; i++))
do
echo >&1000
done
for ((j=1; j<=1000; j++))
do
read -u1000
{
echo $j
echo >&1000
} &
done
wait
echo "done!!!!!!!!!!"
名前付きパイプを使用すると、毎回20個のサブシェルが並列に実行されます。
それが役に立てば幸い:)