6

多くのファイルに対して操作を実行するために単純な for ループを書いていることがよくあります。たとえば、次のようになります。

for i in `find . | grep ".xml$"`; do bzip2 $i; done

私の 4 コア マシンで 1 つのコアしか使用されていないのは少し気のめいるようです.シェル スクリプトに並列処理を追加する簡単な方法はありますか?

編集:私の問題にもう少しコンテキストを導入するために、申し訳ありませんが、最初から明確ではありませんでした!

妥当なサイズのデータ​​セット (通常は 100 ~ 10,000) に対して、グラフのプロット、圧縮または解凍、または何らかのプログラムの実行など、単純な (っぽい) スクリプトを実行したいことがよくあります。このような問題を解決するために私が使用するスクリプトは上記のように見えますが、別のコマンド、または実行する一連のコマンドが含まれている場合があります。

たとえば、今私は実行しています:

for i in `find . | grep ".xml.bz2$"`; do find_graph -build_graph $i.graph $i; done

したがって、私の問題は bzip 固有のものではありません! (並列 bzip はクールに見えますが、将来的に使用するつもりです)。

4

8 に答える 8

14

解決策xargs並行して実行するために使用します(オプションを忘れないでください-n!)

find -name \*.xml -print0 | xargs -0 -n 1 -P 3 bzip2
于 2008-11-11T21:20:37.717 に答える
6

この perl プログラムはあなたのニーズにかなり合っています。これを行うだけです:

runN -n 4 bzip2 `find . | grep ".xml$"`
于 2008-11-11T19:53:33.447 に答える
4

gnu make には、あなたのケースで機能する優れた並列処理機能 (例: -j 5) があります。メイクファイルを作成する

%.xml.bz2 : %.xml


all: $(patsubt %.xml,%xml.bz2,$(shell find . -name '*.xml') ) 

それから

nice make -j 5

「5」を何らかの数値に置き換えます。おそらく、CPU の数よりも 1 つ多い数値です。あなたがマシンを使用している間に他の誰かがマシンを使用したい場合に備えて、これを「ナイス」にしたいかもしれません。

于 2008-11-11T20:53:18.040 に答える
2

一般的な質問への答えは、並列化するものの詳細に依存するため、難しいものです。一方、この特定の目的のためには、単純な bzip2 の代わりに pbzip2 を使用する必要があります (pbzip2 が既にインストールされているか、少なくともリポジトリまたはディストリビューションにある可能性があります)。詳細はこちら:http: //compression.ca/pbzip2/

于 2008-11-11T19:53:49.173 に答える
2

この種の操作は逆効果だと思います。その理由は、より多くのプロセスが同時にディスクにアクセスすると、読み取り/書き込み時間が長くなるため、最終結果がより長い時間で終了するためです。ここでのボトルネックは、コア数に関係なく、CPU の問題ではありません。

単純な 2 つの大きなファイルを同じ HD ドライブに同時にコピーしたことはありませんか? 私は通常、次から次へとコピーする方が高速です。

このタスクにはいくらかの CPU パワーが必要であることはわかっていますが (bzip2 は圧縮方法が要求されます)、すべての技術者が必要以上に頻繁に選択する傾向がある「困難な」パスに進む前に、最初の CPU 負荷を測定してみてください。

于 2008-11-11T20:00:55.837 に答える
2

私はbashのためにこのようなことをしました。並列の make トリックは、1 回限りの場合はおそらくはるかに高速ですが、bash でこのようなものを実装するためのメイン コード セクションを次に示します。ただし、目的に合わせて変更する必要があります。

#!/bin/bash

# Replace NNN with the number of loops you want to run through
# and CMD with the command you want to parallel-ize.

set -m

nodes=`grep processor /proc/cpuinfo | wc -l`
job=($(yes 0 | head -n $nodes | tr '\n' ' '))

isin()
{
  local v=$1

  shift 1
  while (( $# > 0 ))
  do
    if [ $v = $1 ]; then return 0; fi
    shift 1
  done
  return 1
}

dowait()
{
  while true
  do
    nj=( $(jobs -p) )
    if (( ${#nj[@]} < nodes ))
    then
      for (( o=0; o<nodes; o++ ))
      do
        if ! isin ${job[$o]} ${nj[*]}; then let job[o]=0; fi
      done
      return;
    fi
    sleep 1
  done
}

let x=0
while (( x < NNN ))
do
  for (( o=0; o<nodes; o++ ))
  do
    if (( job[o] == 0 )); then break; fi
  done

  if (( o == nodes )); then
    dowait;
    continue;
  fi

  CMD &
  let job[o]=$!

  let x++
done

wait
于 2008-11-11T21:10:00.860 に答える
1

今日問題を解決しなければならない場合は、おそらく GNU Parallel のようなツールを使用することでしょう (ただし、タスクに特化した並列化ツールが存在しない場合pbzip2):

find . | grep ".xml$" | parallel bzip2

詳しく知ることができ:

于 2014-03-05T22:48:59.700 に答える
1

私はあなたが次のことができると思います

for i in `find . | grep ".xml$"`; do bzip2 $i&; done

ただし、ファイルがすぐにあるため、多くのプロセスがスピンオフし、一度に 4 つのプロセスを実行するだけでは最適ではありません。

于 2008-11-11T19:46:52.010 に答える