Bashで開始されたプログラムの数を制御する

Bashで開始されたプログラムの数を制御する

私は研究プロジェクトの一環として、大量のデータを複数のファイルに分割して処理しています。

フォルダ内のすべてのファイルは、フォルダ内のすべての要素に関連するスクリプトとして処理する必要がありfooます。myScriptbar

これは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私のスクリプトは期待どおりに動作しません。

私の質問はこんな感じです。より簡単な方法がありますか?どちらがより安定していますか?

ノードで他のタスクを実行しないため、発生するすべてのタスクはスクリプトによって発生します。

答え1

シェルスクリプトを使用してこれを行うことはできますが、難しいです。シェルスクリプトは、いくつかのバックグラウンドタスクを実行するのにあまりうまくいきません。

私の提案は以下を使用することです。GNUが作るあるいは、異なるバージョンの make は、複数のジョブを並列-jに実行することを選択できます。各サブタスクを makefile ルールで作成します。

以下のメイクファイルの部分があなたのルールを実装しているようですが、あなたのコードは従うのが難しいので、今すぐ結果が得られた可能性があります。最初の行は、入力ファイルの出力ファイルを列挙します(注:入力ファイルを上書きしないでください。何らかの理由でジョブが途中で停止した場合、処理されたかどうか不明なデータが残ります)。インデントされた行は実行するコマンドです。 8つのスペースの代わりにタブを使用して各コマンドをインデントします。このコマンドでは、ソースファイル(file)を$<表し、ターゲットファイル(file)を表し、拡張子のないターゲットです。シェルコマンドのすべてのシンボルは2倍にする必要があり、改行を抑制するために末尾にを追加しない限り、各コマンドラインは別々のサブシェルで実行されます(シェルでは開始と終了が1行の長い行として表示されます)。.in$@.out$*$\set -edone

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

答え2

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

答え3

ulimitbashのマニュアルページで試すことができます。

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つに制限されます。

しかし、まだテストしていません。

関連情報