シェル操作のための限られたキューを作成するには?

シェル操作のための限られたキューを作成するには?

ソートしたい1000個のgzip圧縮ファイルがあります。

この操作を順番に実行すると、プロセスは非常に簡単に見えます。

find . -name *.gz -exec zcat {} | sort > {}.txt \;

上記のコードが動作するかどうかはわかりませんが(どこでミスをしたら修正してください)、理解できたらと思います。

とにかく、プロセス全体をより速くするためにungzip / sort操作を並列化したいと思います。また、1000個のプロセスが同時に実行されるのを見たくありません。設定可能な容量を持つ限られた作業キュー(JavaのBlockingQueueや.NETのBlockingCollectionなど)があれば良いでしょう。この場合、10個のプロセスのみが並列に実行されます。

シェルでこれを行うことはできますか?

答え1

GNU並列処理を使用する:

find . -name *.gz | parallel --files 'zcat {} | sort' | parallel -X -j1 sort -m {} ';' rm {} > sorted

次のように簡単にGNU Parallelをインストールできます。

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

詳しくは、紹介ビデオをご覧ください。https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1このチュートリアル(man parallel_tutorial)を見てください。あなたはコマンドラインが大好きです。

答え2

私はこの仕事を選びますmake(1)。シェルではありませんが、make(1)jobserverはあなたが望むものとほぼ正確に一致し、make(1)これに適した機能を備えています。行のgzip -cd先頭にはタブがインデントされています。これは非常に重要です。 (make(1)たまにはちょっと古いような感じもする時があります。)

$ cat Makefile 
TXT := $(wildcard *.gz)

all: $(TXT:.gz=.txt)

%.txt:%.gz
    gzip -cd $< | sort > $@
$ cp /usr/share/man/man2/*.gz .
$ ls -l
total 1992
-rw-r--r-- 1 sarnold sarnold  4447 2011-12-06 00:22 aa_change_hat.2.gz
-rw-r--r-- 1 sarnold sarnold  3977 2011-12-06 00:22 aa_change_profile.2.gz
-rw-r--r-- 1 sarnold sarnold  5082 2011-12-06 00:22 accept.2.gz
...
$ time make -j 10
gzip -cd aa_change_hat.2.gz | sort > aa_change_hat.2.txt
gzip -cd aa_change_profile.2.gz | sort > aa_change_profile.2.txt
gzip -cd accept.2.gz | sort > accept.2.txt
gzip -cd accept4.2.gz | sort > accept4.2.txt
gzip -cd access.2.gz | sort > access.2.txt
...
gzip -cd write.2.gz | sort > write.2.txt
gzip -cd writev.2.gz | sort > writev.2.txt

real    0m0.259s
user    0m0.190s
sys 0m0.020s
$ rm w*txt
$ make
gzip -cd wait.2.gz | sort > wait.2.txt
gzip -cd wait3.2.gz | sort > wait3.2.txt
gzip -cd wait4.2.gz | sort > wait4.2.txt
gzip -cd waitid.2.gz | sort > waitid.2.txt
gzip -cd waitpid.2.gz | sort > waitpid.2.txt
gzip -cd write.2.gz | sort > write.2.txt
gzip -cd writev.2.gz | sort > writev.2.txt
$ 

rm w*txtこのコマンドは、タスクを完了するmake(1)ために必要な最小限のタスクのみをインテリジェントに実行します。

答え3

Google を少し見てみると、次のような興味深いアプローチがわかります。http://pebblesinthesand.wordpress.com/2008/05/22/a-srcipt-for-running-processes-in-parallel-in-bash/

for ARG in  $*; do
    command $ARG &
    NPROC=$(($NPROC+1))
    if [ "$NPROC" -ge 4 ]; then
        wait
        NPROC=0
    fi
done

答え4

GNUを使用すると、xargs次のことができます。

xargs -P4 -n 10 -r0a <(find . -name '*.gz' -type f -print0) sh -c '
  for file do
    zcat < "$file" | sort > "$file.txt"
  done' sh {} +

これは最大4つのファイルを並列に呼び出しsh、各ファイルはループ内で順番に最大10個のファイルを処理します。

関連情報