私の研究プロジェクトの一環として、私は大量のデータを多くのファイルに分割して処理しています。
フォルダfoo
内のすべてのファイルは、フォルダmyScript
のすべての要素を含むスクリプトbar
によって処理される必要があります。
これはmyScript
です:
for f in bar/*
do
awk 'NR==FNR{a[$0]=$0;next}!a[$0]' $f $1 > tmp
cp tmp $1
done
Forループですべてのファイルを処理するという最初のアイデアは有効です。
for f in foo/*
do
./myScript $f
done
ただし、これには永遠に時間がかかります。 &
を追加してバックグラウンドですべてのmyScriptを開始するだけで、大量の入力を伴うawk
とcp
の何千もの並列実行インスタンスが作成されますが、これは明らかに悪いことです。
以下で作成する「スレッド」の数を制限することを考えました
for f in foo/*
do
THREAD_COUNT=$(ps | wc -f)
while [ $THREAD_COUNT -ge 12 ]
do
sleep 1
THREAD_COUNT=$(ps | wc -f)
done
./myScript $f &
done
補足:ノードに8つのコアがあり、常にbash
、ps
、wc
が実行されているため、12と比較しています。 ps | wc -l
の呼び出し時のヘッダー行。
残念ながら、myScript
を呼び出すと、ps
に複数のエントリが追加されるため、スクリプトの動作が意図したとおりになりませんでした。
だからここに私の質問があります:もっと簡単な方法はありますか?より安定した方法は?
私はノードで他に何もしていないので、起こっていることはすべてスクリプトによってのみ引き起こされます。
シェルスクリプトを使用してこれを行うことはできますが、これは困難な方法です。シェルスクリプトは、複数のバックグラウンドジョブの操作があまり得意ではありません。
GNU make または-j
オプションを持つ他のバージョンのmakeを使用して、複数のジョブを並行して実行することをお勧めします。各サブタスクをメイクファイルルールとして記述します。
以下のmakefileスニペットはあなたのルールを実装していると思いますが、あなたのコードは従うのが難しかったので、私は今それを正しく理解しているかもしれません。最初の行は、入力ファイルからの出力ファイルを列挙します(注:入力ファイルを上書きしないでください!何らかの理由でジョブが途中で停止すると、処理されたかどうかわからないデータになってしまいます) 。インデントされた行は、実行するコマンドです。タブを使用して、8つのスペースではなく、各コマンドをインデントします。これらのコマンドで、$<
はソースファイル(.in
ファイル)を表し、$@
はターゲット(.out
ファイル)を表し、$*
はターゲットを表しますその拡張子なし。シェルコマンドのすべての$
記号は2倍にする必要があり、改行をキャンセルする\
を最後に配置しない限り、各コマンドラインは個別のサブシェルで実行されます(したがって、シェルはで始まる1つの長い行を認識します) set -e
で終わりdone
)。
all: $(patsubst %.in,%.out,$(wildcard foo/*.in))
%.out: %.in
cp $< $*.tmp.in
set -e; \
for f in bar/*; do \
awk 'NR==FNR{a[$$0]=$$0;next}!a[$$0]' $$f $*.tmp.in >$*.tmp.out; \
mv $*.tmp.out $*.tmp.in; \
done
mv $*.tmp.in $@
これをMakefile
というファイルに入れ、make -j12
を呼び出します。
GNU Parallel(http://www.gnu.org/software/parallel/)を使用すると、次のようになります。
parallel awk \'NR==FNR\{a\[\$0\]=\$0\;next\}\!a\[\$0\]\' {1} {2} '>{2}.tmp; mv {2}.tmp {2}' ::: bar/* ::: foo/*
これにより、コアごとに1つのジョブが実行されます。使用する -j150%
コアごとに1.5ジョブを実行します。
複数のmyScript
を並行して実行したい場合は、次のようにします。
parallel ./myScript ::: foo/*
詳細については、紹介動画をご覧ください: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
ulimit
を使用してみてください。 bashのmanページから:
ulimit [-HSTabcdefilmnpqrstuvx [limit]]
Provides control over the resources available to the Shell and to processes started by it,
on systems that allow such control.
[...]
-u The maximum number of processes available to a single user
だからあなたがulimit -u 8
スクリプト内の適切な位置に、そのシェルで使用可能なプロセスを8に制限します。
しかし、それをテストしませんでした。