次のbashスクリプトがあります。
for i in {0800..9999}; do
for j in {001..032}; do
wget http://example.com/"$i-$j".jpg
done
done
すべての写真がそこにあり、実際には各反復は他の反復に依存しません。スレッド数を並列化して制御する方法は何ですか?
答え1
Confiqの答えは小さなi
合計に対してうまく機能しますj
。ただし、質問のi
合計サイズを考慮すると、j
生成されるプロセスの総数を制限できます。parallel
コマンドまたはいくつかのバージョンを使用できますxargs
。たとえば、-P
このフラグをサポートするxargsを使用すると、次のように内部ループを並列化できます。
for i in {0800..9999}; do
echo {001..032} | xargs -n 1 -P 8 -I{} wget http://example.com/"$i-{}".jpg
done
GNUパラレルより複雑な動作が必要な場合は多数の機能が提供され、次の2つのパラメータを使用して簡単に並列化できます。
parallel -a <(seq 0800 9999) -a <(seq 001 032) -P 8 wget http://example.com/{1}-{2}.jpg
答え2
これは非常に簡単な方法です。この例では、スレッドを10個に制限しています。
for i in {0800..9999}; do
for j in {001..032}; do
wget http://example.com/"$i-$j".jpg &
while test $(jobs -p|wc -w) -ge 10; do sleep 0.1 ; done
done
done
答え3
for i in {1..3}; do
for j in {10..20}; do
(wget http://example.com/"$i-$j".jpg &)
done
done
テストもしてみたけど…
答え4
parallel
使用できない環境で同じ問題を解決した方法は、次のとおりです。これはbash機能に依存するため、#!/bin/bash
明示的にまたはbashを介してスクリプトを実行する必要があります。
MAX_CONCURRENT=50
n=0
some_command_that_outputs_urls \
| while read url
do
{
do_something_with $url
} &
PIDS="$PIDS $!"
((++n))
if test "$n" -ge "$MAX_CONCURRENT"
then
n=0
wait $PIDS
PIDS=""
fi
done
test -n "$PIDS" && wait $PIDS
$MAX_CONCURRENT
必要な(おおよその)最大スレッド数を指定するように調整できます。もちろん、シナリオに適したものとsome_command_that_outputs_urls
何でも変えることができます。do_something_with $url
たとえば、次の行を次のようsome_command_that_outputs_urls \
に置き換えることができます。
for i in {0800..9999}; do
for j in {001..032}; do
printf 'http://example.com/%s-%s.jpg\n' $i $j
done
done \
# ...| while read url ...
そしてdo_something_with $url
簡単に
wget $url
最終結果を教えてください。
MAX_CONCURRENT=50
n=0
for i in {0800..9999}; do
for j in {001..032}; do
printf 'http://example.com/%s-%s.jpg\n' $i $j
done
done \
| while read url
do
{
wget $url
} &
PIDS="$PIDS $!"
((++n))
if test "$n" -ge "$MAX_CONCURRENT"
then
n=0
wait $PIDS
PIDS=""
fi
done
test -n "$PIDS" && wait $PIDS
仕組みは、コマンドを使用して標準出力にURLリストを作成し(この場合)、一度に1行ずつループに読み込むことですwhile
(改行に注意してください)。$MAX_CONCURRENT
同時プロセスを作成して、生成された$n
プロセスの数を追跡し、$PIDS
そのプロセスIDを記録します。プロセスが作成されると$MAX_CONCURRENT
(実際に生成されるのは複合ステートメントであるため、複数のコマンドまたはブロックを含めることができます)、生成されたwait
PIDになります(または指定されたPIDがまだ実行されていない場合はすぐに返されます)。他の実行を続行する前に内部状態をリセットしてください。
再利用されたPIDをよりよく処理することを含め、このスクリプトを改善する方法がありますが、実行する必要がある環境で私が望むことをするので、私にとっては十分です。実際のバージョンではタイムアウトも設定され、cronを介して定期的に実行を再実行するため、この単純なバージョンと比較して実行時間の暴走リスクが大幅に削減されます。