シェルでのGREPの機能に本当に驚いています。以前はJavaでsubstringメソッドを使用していましたが、今ではGREPを使用して数秒で実行され、以前使用していたJavaコードよりも非常に高速です。 (私の経験によれば、私は間違っているかもしれません)
それがどのように起こっているのか理解できなかったと言われていますか?また、ウェブ上で利用できるものはあまりありません。
誰かがこれを手伝ってくれる?
シェルでのGREPの機能に本当に驚いています。以前はJavaでsubstringメソッドを使用していましたが、今ではGREPを使用して数秒で実行され、以前使用していたJavaコードよりも非常に高速です。 (私の経験によれば、私は間違っているかもしれません)
それがどのように起こっているのか理解できなかったと言われていますか?また、ウェブ上で利用できるものはあまりありません。
誰かがこれを手伝ってくれる?
回答:
あなたの質問がGNU grep
特に関係していると仮定します。これは作者のマイク・ハーテルからのメモです:
GNU grepは、すべての入力バイトを探すことを避けるため、高速です。
それはそれがあること、各バイトのために非常に少数の命令を実行しているため、GNU grepのは速いです しを見て。
GNU grepは、よく知られているBoyer-Mooreアルゴリズムを使用します。このアルゴリズムは、最初にターゲット文字列の最後の文字を探し、ルックアップテーブルを使用して、一致しない文字が見つかったときに、入力をどれだけ先にスキップできるかを伝えます。
GNU grepはまた、Boyer-Mooreの内部ループを展開し、展開されたすべてのステップでループ終了テストを実行する必要がないように、Boyer-Mooreデルタテーブルエントリを設定します。この結果、制限内では、GNU grepは実際に参照する各入力バイトに対して実行されるx86命令の平均が3つ未満になります(そして、多くのバイトを完全にスキップします)。
GNU grepは生のUnix入力システムコールを使用し、データを読み取った後にデータをコピーしません。さらに、GNU grepは入力を行に分割しないようにします。改行を探すと、grepが数倍遅くなります。改行を見つけるには、すべてのバイトを調べる必要があるためです。
したがって、行指向の入力を使用する代わりに、GNU grepは生データを大きなバッファーに読み取り、Boyer-Mooreを使用してバッファーを検索します。一致が見つかった場合にのみ、境界改行を探します(次のような特定のコマンドラインオプション- nこの最適化を無効にします。)
スティーブの優れた答えに追加します。
それは広く知られているわけではないかもしれませんが、長いパターンでは、ボイヤー・ムーアはより長い歩幅で前にスキップしてさらに優れたサブリニア速度を実現できるため、長いパターン文字列をgrep する場合、grepはほとんど常に高速です。
例:
# after running these twice to ensure apples-to-apples comparison
# (everything is in the buffer cache)
$ time grep -c 'tg=f_c' 20140910.log
28
0.168u 0.068s 0:00.26
$ time grep -c ' /cc/merchant.json tg=f_c' 20140910.log
28
0.100u 0.056s 0:00.17
長いフォームは35%高速です!
どうして?Boyer-Mooreは、パターン文字列からスキップ転送テーブルを構築し、不一致がある場合は常に、入力内の単一の文字をスキップテーブル内の文字と比較する前に、可能な限り長いスキップ(最後の文字から最初の文字まで)を選択します。
ここだボイヤームーア説明するビデオ (kommradHomerの功績は)
別の一般的な誤解(GNU grepの場合)は、fgrep
よりも速いということですgrep
。f
in fgrep
は「高速」を意味せず、「固定」を意味します(manページを参照)。両方とも同じプログラムであり、両方ともBoyer-Mooreを使用しているため、fixed-を検索するときに速度に違いはありません正規表現の特殊文字のない文字列。私が使用する唯一の理由fgrep
は、正規表現の特殊文字(、、またはなど)がある.
場合に[]
、そのように*
解釈されないようにすることです。そしてそれでも、よりポータブル/標準の形式grep -F
が優先されfgrep
ます。
xs.txt
に100000000 'x'が含まれているとするとgrep yx xs.txt
、実際にはそうなりますが、実際にはそうするよりも早く一致を見つけることができませんgrep yxxxxxxxxxxxxxxxxxxx xs.txt
。その場合、Boyer-Moore-HorspoolからBoyer-Mooreへの改善により、Skip-Aheadが改善されますが、一般的なケースでは、おそらく3つの機械命令だけではありません。
grep/fgrep/egrep
が同じ実行可能ファイルへのすべてのハードリンクであった時代は過ぎ去ったようです。それら(およびz*grep
bz*grep
その場で解凍するutilsのような他の拡張機能)は、今では小さなシェルラッパーになっていgrep
ます。いくつかの単一の実行可能&シェルラッパーの間で、スイッチ上の興味深い歴史的なコメントは、このコミットで見つけることができます:git.savannah.gnu.org/cgit/grep.git/commit/...を