1. ホーム
  2. bash

[解決済み] Bashでwgetを並列化する [重複].

2023-07-18 04:43:53

質問

私はウェブサイトから比較的小さなページの束を取得しており、どうにかしてBashで並行してそれを行うことができないかと考えていました。現在、私のコードは次のようになりますが、実行に時間がかかります (私を遅くしているのは、接続の待ち時間だと思います)。

for i in {1..42}
do
    wget "https://www.example.com/page$i.html"
done

xargsを使用することを聞いたことがありますが、私はそれについて何も知らないし、マニュアルページは非常にわかりにくいです。 何かアイデアはありますか?これを並列で行うことは可能でしょうか?これを攻撃するために行くことができる他の方法はありますか?

どのように解決するのですか?

を押すことが望ましいです。 wget を背景に押し出す方がはるかに好ましいです。 & または -b を使用することができます。 xargs を使うと、同じ効果、より良い効果が得られます。

利点は xargs 正しく同期する を追加作業なしで実行します。これは、ダウンロードしたファイルに安全にアクセスできることを意味します(エラーが発生しないことを前提としています)。すべてのダウンロードが完了(または失敗)した時点で xargs が終了すると、すべてのダウンロードが完了(または失敗)し、 すべてがうまくいったかどうかを終了コードで知ることができます。この方法は sleep で忙しく待ち、手動で完了をテストするよりもずっと好ましいことです。

と仮定して URL_LIST がすべての URL を含む変数であると仮定して(OP の例ではループで構築できますが、手動で生成したリストでもかまいません)、これを実行します。

echo $URL_LIST | xargs -n 1 -P 8 wget -q

は一度に一つの引数を渡します ( -n 1 ) を wget を実行し、最大8つの並列 wget プロセスを同時に実行します ( -P 8 ). xarg は最後に生成されたプロセスが終了した後に返されます。 これはまさに私たちが知りたかったことです。余分なトリックは必要ありません。

私が選択した 8 並列ダウンロードというマジック ナンバーは明確なものではありませんが、おそらく良い妥協点だと思います。一連のダウンロードを最大化するには、2 つの要素があります。

1 つは、ケーブルを埋めること、つまり、利用可能な帯域幅を利用することです。通常の条件 (サーバーの帯域幅がクライアントより大きい) を仮定すると、1 つまたはせいぜい 2 つのダウンロードですでにこのような状態になっています。この問題にさらに接続を投入すると、パケットがドロップされ、TCP 輻輳制御が作動するだけであり、また N のダウンロードで、漸近的に 1/N の各帯域幅で、同じ正味の効果 (ドロップされたパケットを差し引き、ウィンドウ サイズの回復を差し引く) を得ることができます。パケットを廃棄することは IP ネットワークで起こる普通のことで、輻輳制御は (単一接続であっても) このように機能することになっており、通常、その影響は実質的にゼロです。しかし、不当に多くの接続があると、この影響が増幅されるため、目立ってくることがあります。いずれにせよ、これによって何かが速くなるわけではありません。

2つ目の要因は、接続の確立とリクエストの処理です。ここで、飛行中の余分な接続をいくつか持つことは は本当に役に立ちます。 . 問題は、2往復の遅延 (通常、同じ地域内では 20-40ms 、大陸間では 200-300ms) と、サーバーが実際にリクエストを処理し、ソケットに応答を送るのに必要な奇妙な 1-2 ミリ秒の遅延です。これは大した時間ではありません。 それ自体 しかし、数百/数千のリクエストに乗算されると、それはすぐに積み重なります。

飛行中に半ダースから1ダースのリクエストがあると、この遅延のほとんどまたはすべてが隠れます(まだありますが、重なっているので、合計されません!)。同時に、わずか数回の同時接続は、過度の輻輳を引き起こしたり、サーバーに新しいプロセスをフォークさせたりするような悪影響を与えません。