web-dev-qa-db-ja.com

非常に多くの反復でforループを並列化する

ループ内の反復回数が10 ^ 6のように非常に大きくなる可能性がある、forループを並列化したいと思います。ですから、プロセスよりもスレッドを作成できればもっと良いでしょう。どうやってするの?コードは次のとおりです

N=$1

for (( i=0; i < $N; i++ )); do

    ./random >> output /* in each iteration one random number is appended to
                          a file "output" */                                

done
3
  1. シェルからスレッドを生成することはできません。
  2. 複数のプロセスから同じファイルに書き込みたくない。
  3. randomプログラムが単一の数値を生成するだけの場合、
    • ループがioバウンドになるのに十分な速さである必要があります。
    • 可能であれば、それを編集して引数を取り、その数の数値を出力する必要があります。
    • 実際の実行がボトルネックである場合は、数値の生成方法を再考する必要があります。おそらく、コードを コードレビュー に投稿してください。

あなたが本当に本当にそれでもこのようにしたいのなら、チャンクでそれをしてください:

for i in {0..9}; do
    for ((j = 1; j < $N/10; j++)); do
        ./random
    done > tmp$i &
    pid[$i]=$?
done
for i in {0..9}; do
    wait ${pid[$i]}
done
cat tmp{0..9} >> outfile
11
Kevin

新しいスレッドを手動で作成できるシェルを私は知りません。通常、現在のシェルの既存のスレッドのみを利用できます(または、実際には新しいプロセスであるサブシェルを作成できます)。代わりにpythonまたは別の言語を使用してください。

できたとしても、この規模の何かにシェルスクリプトを使用することはお勧めしません。 10 ^ 6回の反復を実行すると、コンパイルされた言語と比較してパフォーマンスが大幅に低下する可能性があります。

4
Chris Down

いつものように、問題はリソースの競合です。同時に実行されるプロセス/スレッドの数を制限する必要があります。

また、並行スレッドを持つことは、実行される処理のタイプに大きく依存します。メモリ、CPU、I/Oなどのプログラミングが適切に組み合わされていると、はるかに優れています。すべてのサブプロセスがすべてのCPUを実行する場合、一度に10〜20を実行しても何も高速化されません。処理を他のマシンにファームアウトすることを試みることができます。例えばsshを使用して他のマシンで呼び出しを開始し、結果を取得します。

迅速で汚れた最初のパスは、次のようなものです。

N=$1 # max number to iterate on
shift # rest of command line is the command to run: e.g. "./random"
maxcount=10 # maximum in the pool
curcount=0  # how many currently in the pool
reaper () {
    wait
    curcount=`expr $curcount - 1`
}
spawnnext () {
    n=$1
    shift
    while [ $curcount -ge $maxcount ]; do
        sleep 1 # wait for a free slot in the pool
    done
    echo $n
    "$@" &
    curcount=`expr $curcount + 1`
}

trap 'reaper' CHLD

for (( i=0; i < $N; i++)); do
    spawnnext $i "$@"
done

注意;私はこれをテストしていません。その場でそれを書いただけです。

しかし、私はこれをPythonなどのより高レベルでパフォーマンスの高い言語で行います: https://stackoverflow.com/questions/3033952/python-thread-pool-similar-to-the-multiprocessing-pool

2
Arcege

タスクが単に乱数を生成することである場合:

Perl -e 'for($t=0;$t<1000000;$t++) { print int(Rand()*1000),"\n" }'

あなたのタスクが本当に何か他のものであるなら、あなたはGNU Parallel:

parallel ./random :::: <(seq 1000000) > output

GNU Parallelは、次の方法で簡単にインストールできます。

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel

詳細については、紹介ビデオをご覧ください: http://pi.dk/1

1
Ole Tange