多くのファイルを処理したいのですが、ここにたくさんのコアがあるので、並行して処理したいと思います。
for i in *.myfiles; do do_something $i `derived_params $i` other_params; done
Makefile solution を知っていますが、コマンドにはシェルグロブリストからの引数が必要です。私が見つけたのは:
> function pwait() {
> while [ $(jobs -p | wc -l) -ge $1 ]; do
> sleep 1
> done
> }
>
これを使用するには、ジョブとpwait呼び出しの後に、並列プロセスの数を指定するだけです。
> for i in *; do
> do_something $i &
> pwait 10
> done
しかし、これはあまりうまく機能しません。私はそれを例えばで試しました多くのファイルを変換するforループですが、エラーが発生し、ジョブが取り消されました。
Zshメーリングリストでの議論は今ではとても古いので、これがまだ行われていないとは信じられません。それで、あなたはもっとよく知っていますか?
Makefile is問題の良い解決策です。この並列実行をシェルでプログラムすることもできますが、お気づきのように難しいです。 makeの並列実装は、ジョブの開始と終了の検出を処理するだけでなく、注意が必要な負荷分散も処理します。
グロブの要件は障害ではありません。それをサポートするmake実装があります。 GNU make、$(wildcard *.c)
などのワイルドカード拡張と$(Shell mycommand)
などのシェルアクセス(GNU詳細についてはmanualを作成してください)。これはLinuxではデフォルトのmake
であり、他のほとんどのシステムで使用できます。ニーズに適応できる可能性のあるMakefileスケルトンは次のとおりです。
sources = $(wildcard * .src) all:$(sources:.src = .tgt) %。tgt: $ .src do_something $ <$$(derivated_params $ <)> $ @
make -j4
のようなものを実行して4つのジョブを並行して実行するか、make -j -l3
のようなものを実行して負荷の平均を約3に保ちます。
派生した引数がどのようなものかわかりません。しかし、GNU Parallel http:// www.gnu.org/software/parallel/を使用すると、cpuコアごとに1つのジョブを実行できます。
find . | parallel -j+0 'a={}; name=${a##*/}; upper=$(echo "$name" | tr "[:lower:]" "[:upper:]");
echo "$name - $upper"'
導出したいのが単に.extensionを変更することである場合、{。}は便利かもしれません:
parallel -j+0 lame {} -o {.}.mp3 ::: *.wav
GNU Parallel at http://www.youtube.com/watch?v=OpaiGYxkSuQ の紹介ビデオをご覧ください
シェルのwait
コマンドを使用してもうまくいきませんか?
for i in *
do
do_something $i &
done
wait
ループはジョブを実行して待機し、次のジョブを実行します。上記がうまくいかない場合は、pwait
の後にdone
を移動するとうまくいく可能性があります。
なぜ誰もxargsについてまだ言及していないのですか?
ちょうど3つの引数があると仮定すると、
for i in *.myfiles; do echo -n $i `derived_params $i` other_params; done | xargs -n 3 -P $PROCS do_something
それ以外の場合は区切り文字を使用します(nullはそのために便利です):
for i in *.myfiles; do echo -n $i `derived_params $i` other_params; echo -ne "\0"; done | xargs -0 -n 1 -P $PROCS do_something
編集:上記の場合、各パラメーターはヌル文字で区切る必要があり、パラメーターの数はxargs-nで指定する必要があります。
私はいくつかの答えを試しました。これらは、スクリプトを必要以上に複雑にします。理想的にはparallel
またはxargs
を使用することをお勧めしますが、forループ内の操作が複雑な場合、並列に提供する大きくて長い行のファイルを作成するのは問題になる可能性があります。代わりに、次のようにソースを使用できます
# Create a test file
$ cat test.txt
task_test 1
task_test 2
# Create a Shell source file
$ cat task.sh
task_test()
{
echo $1
}
# use the source under bash -c
$ cat test.txt | xargs -n1 -I{} bash -c 'source task.sh; {}'
1
2
したがって、あなたの問題の解決策は次のようになります
for i in *.myfiles; echo " do_something $i `derived_params $i` other_params
" >> commands.txt ; done
何かをすることをdo_something.sh
として定義する
do_something(){
process $1
echo $2
whatever $3
}
xarg
またはgnu parallel
で実行します
cat commands.txt | xargs -n1 -I{} -P8 bash -c 'source do_something.sh; {}'
Forの反復の機能的独立性が暗示されていると思います。