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

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

10000ワード(1行に1ワード)を含むWords.txtがあります。 5,000の文書があります。どの文書にどの単語が含まれているかを確認したい(単語の周りの正規表現パターンを使用)。ドキュメントをgrepしてヒットを出力するscript.shがあります。私は(1)入力ファイルを小さなファイルに分割し、(2)各ファイルをscript.shの引数として提供し、(3)すべてのファイルを並列に実行したいと思います。

私の試みは以下に基づいています。地図時間エラーが発生しました。

$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コマンドが起動されたディレクトリ内のファイルを介して出力をディレクトリループに分割できるとします。しかし、これをエレガントで簡潔に(並列処理を使用して)行う方法は何ですか?

答え1

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行を最も効率的にキャッチする方法について説明しています。https://www.gnu.org/software/parallel/parallel_examples.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がCPUの90%を超える場合(例:top実行時)、CPUは制限要因であるため、並列化がスピードアップします。そうでない場合、ディスクI / Oは制限要因であり、ディスクシステムによっては並列化が速くなったり遅くなったりする可能性があります。確かに知っている唯一の方法は測定することです。

CPUが制限要素の場合は、正規表現を並列化する必要があります。

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

これはCPUごとに1つのgrepを起動し、CPUごとに1回大きなファイルを読み取ります。ただし、これは並行して実行されるため、最初の読み取り以外のすべての読み取りはRAMにキャッシュされます。 regexp.txtのサイズによっては、-L1000の代わりに--block 10mを使用する方が速いかもしれません。 regexp.txtが大きすぎてRAMに収まらない場合は、--round-robinを削除して-L1000を調整してください。これにより、ビッグファイルをもっと読むことができます。

一部のストレージシステムは、複数のブロックを並列に読み取る場合にパフォーマンスが向上します。これは、いくつかのRAIDシステムといくつかのネットワークファイルシステムに当てはまります。大容量ファイルを並列に読み取る:

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

これにより、ビッグファイルが100 MBのチャンクに分割され、各チャンクに対してgrepが実行されます。 bigfile と regexp.txt を並列に読み取るには、--fifo を使って 2 つを結合します。

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

答え2

このsplitツールを使用すると、次のことができます。

split -l 1000 words.txt words-

ファイルを複数のファイルに分割しますwords.txt。各ファイルの名前は1000行以下で指定する必要があります。

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

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

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

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

関連情報