web-dev-qa-db-ja.com

ファイルを分割し、各部分をパラメータとしてスクリプトに渡し、各スクリプトを並行して実行します

10000語(1行に1つ)のwords.txtがあります。 5,000のドキュメントがあります。どのドキュメントにそれらの単語のどれが含まれているかを確認したい(Wordの周りに正規表現パターンがある)。ドキュメントを取得してヒットを出力するscript.shがあります。 (1)入力ファイルをより小さなファイルに分割し、(2)各ファイルをパラメーターとしてscript.shにフィードし、(3)これらすべてを並行して実行したいと思います。

tutorial に基づく私の試みはエラーをヒットしています

$parallel ./script.sh ::: split words.txt # ./script.sh: line 22: split: No such file or directory

私のscript.shは次のようになります

#!/usr/bin/env bash

line 1 while read line
line 2  do
        some stuff
line 22 done < $1

Grepコマンドを起動するディレクトリ内のファイルを介してディレクトリループに分割を出力できると思いますが、これをエレガントかつ簡潔に(並列を使用して)行うにはどうすればよいですか?

5
bernie2436

splitツールを使用できます。

split -l 1000 words.txt words-

words.txtファイルをそれぞれ1000行以内の名前のファイルに分割します

words-aa
words-ab
words-ac
...
words-ba
words-bb
...

プレフィックス(上記の例ではwords-)を省略すると、splitはデフォルトのプレフィックスとしてxを使用します。

生成されたファイルをparallelで使用するには、globを使用できます。

split -l 1000 words.txt words-
parallel ./script.sh ::: words-[a-z][a-z]
4
Joseph R.

STDINから読み取るため、おそらく一時ファイルは必要ありません。したがって、splitを使用する理由は実際にはありません。 --pipeを使用してファイルを削除します。

cat words | parallel --pipe -L 1000 -N1 ./script.sh

それが本当に必要なgrepである場合:

find dir-with-5000-files -type f | parallel -X grep -f words.txt 

words.txtが大きすぎてメモリに収まらない場合は、次のように分割できます。

find dir-with-5000-files -type f | parallel -X "cat words.txt | parallel --pipe grep -f -"

GNU Parallelのマニュアルページでは、m個の正規表現に対してn行を最も効率的にgrepする方法について説明しています。 http://www.gnu.org/software/parallel/man.html# example__grepping_n_lines_for_m_regular_expressions _

多くの正規表現の大きなファイルをgrepする最も簡単な解決策は次のとおりです。

grep -f regexps.txt bigfile

または、正規表現が固定文字列の場合:

grep -F -f regexps.txt bigfile

CPUとディスクI/Oの2つの制限要因があります。 CPUの測定は簡単です:grepが90%を超えるCPUを使用する場合(たとえば、topを実行している場合)、CPUが制限要因であり、並列化によってこれが高速化されます。そうでない場合は、ディスクI/Oが制限要因であり、ディスクシステムによっては、並列化が高速または低速になる場合があります。確実に知る唯一の方法は、測定することです。

CPUが制限要因である場合、並列化は正規表現で実行する必要があります。

cat regexp.txt | parallel --pipe -L1000 --round-robin grep -f - bigfile

これにより、CPUごとに1つのgrepが開始され、CPUごとに1回bigfileが読み取られますが、並行して実行されるため、最初の読み取りを除くすべての読み取りがRAMにキャッシュされます。 regexp.txtのサイズによっては、-L1000の代わりに--block10mを使用する方が速い場合があります。 regexp.txtが大きすぎてRAMに収まらない場合は、-round-robinを削除し、-L1000を調整します。これにより、bigfileがより多く読み取られるようになります。

一部のストレージシステムは、複数のチャンクを並行して読み取るとパフォーマンスが向上します。これは、一部のRAIDシステムおよび一部のネットワークファイルシステムに当てはまります。 bigfileの読み取りを並列化するには:

parallel --pipepart --block 100M -a bigfile grep -f regexp.txt

これにより、bigfileが100MBのチャンクに分割され、これらの各チャンクでgrepが実行されます。 bigfileとregexp.txtの両方の読み取りを並列化するには、-fifoを使用して2つを組み合わせます。

parallel --pipepart --block 100M -a bigfile --fifo cat regexp.txt \
\| parallel --pipe -L1000 --round-robin grep -f - {}
5
Ole Tange