web-dev-qa-db-ja.com

シェルスクリプトの並列実行

私はシェルスクリプトを持っています

  1. 大きなテキストファイル(600万行と6列)をシャッフルします。
  2. 最初の列に基づいてファイルをソートします
  3. 1000ファイルを出力

擬似コードは次のようになります

file1.sh 

#!/bin/bash
for i in $(seq 1 1000)
do

  Generating random numbers here , sorting  and outputting to file$i.txt  

done

parallelでこのシェルスクリプトを実行して、マルチコアCPUを最大限に活用する方法はありますか?

現時点では、 。/file1.shは1〜1000回のシーケンスで実行され、非常に低速です。

ご協力いただきありがとうございます。

41
Tony

bashサブシェル を確認してください。これらを使用して、スクリプトの一部を並行して実行できます。

私はこれをテストしていませんが、これはスタートかもしれません:

#!/bin/bash
for i in $(seq 1 1000)
do
   ( Generating random numbers here , sorting  and outputting to file$i.txt ) &
   if (( $i % 10 == 0 )); then wait; fi # Limit to 10 concurrent subshells.
done
wait
42
Anders Lindahl

これを行うもう1つの非常に便利な方法は、 gnu parallel を使用することです。まだお持ちでない場合は、インストールする価値があります。これは、タスクに必ずしも同じ時間がかかるとは限らない場合に非常に貴重です。

seq 1000 | parallel -j 8 --workdir $PWD ./myrun {}

./myrun 1./myrun 2などを起動し、一度に8つのジョブが実行されていることを確認します。また、たとえば複数のノードで一度に実行する場合、たとえばPBSジョブで、ノードのリストを取ることができます。システムでこれを行う方法に関するユーザーへの指示は、 here です。

追加するために更新されました:moreutilsパッケージに含まれる同名のより限定されたユーティリティではなく、gnu-parallelを使用していることを確認したい(2つの分岐履歴は ここ で説明されています。)

85
Jonathan Dursi

物事を並行して実行するには、シェルコマンドの最後に「&」を使用してバックグラウンドで実行します。デフォルトでは、waitはすべてのバックグラウンドプロセスが完了するまで待機します(引数なし)。したがって、10を並行して開始し、待機してからさらに10を実行することもできます。これは、2つのネストされたループで簡単に行えます。

13
Tony Delroy

プログラムの全リスト があり、シェルから並行してジョブを実行できます。これには、GNU parallel。多くのソリューションがあります。別の良いニュースは、すべてのコア/プロセッサが常にビジー状態に保たれるように、ジョブのスケジューリングがおそらく非常に効率的であることです。

9
Eric O Lebigot

[〜#〜] ppss [〜#〜] を実行するシンプルで移植可能なプログラムがあります。 PPSSは、使用可能なコアの数を確認し、別のジョブが終了するたびに別のジョブを起動することにより、自動的にジョブをスケジュールします。

4
Eric O Lebigot
IDLE_CPU=1
NCPU=$(nproc)

int_childs() {
    trap - INT
    while IFS=$'\n' read -r pid; do
        kill -s SIGINT -$pid
    done < <(jobs -p -r)
    kill -s SIGINT -$$
}

# cmds is array that hold commands
# the complex thing is display which will handle all cmd output
# and serialized it correctly

trap int_childs INT
{
    exec 2>&1
    set -m

    if [ $NCPU -gt $IDLE_CPU ]; then
        for cmd in "${cmds[@]}"; do
            $cmd &
            while [ $(jobs -pr |wc -l) -ge $((NCPU - IDLE_CPU)) ]; do
                wait -n
            done
        done
        wait

    else
        for cmd in "${cmds[@]}"; do
            $cmd
        done
    fi
} | display
0
Zakaria