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

おすすめ記事