wgetを使用して複数のファイルを並列にダウンロード

wgetを使用して複数のファイルを並列にダウンロード

次の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(実際に生成されるのは複合ステートメントであるため、複数のコマンドまたはブロックを含めることができます)、生成されたwaitPIDになります(または指定されたPIDがまだ実行されていない場合はすぐに返されます)。他の実行を続行する前に内部状態をリセットしてください。

再利用されたPIDをよりよく処理することを含め、このスクリプトを改善する方法がありますが、実行する必要がある環境で私が望むことをするので、私にとっては十分です。実際のバージョンではタイムアウトも設定され、cronを介して定期的に実行を再実行するため、この単純なバージョンと比較して実行時間の暴走リスクが大幅に削減されます。

関連情報