2012-12-11 16 views
13

--ignore-caseオプションをgrepに追加すると、検索が50倍遅くなる可能性があることに非常に驚きました。私は同じ結果を持つ2つの異なるマシンでこれをテストしました。私は、巨大なパフォーマンスの違いについての説明を見つけるのが好奇心です。"grep --ignore-case"が50倍遅いのはなぜですか?

大文字と小文字を区別しない検索のためのgrepの代替コマンドも見たいと思います。正規表現は必要ありません。固定文字列検索だけです。最初のテストファイルは、いくつかのダミーデータで50  メガバイトプレーンテキストファイルになります、あなたはそれを生成するために、次のコードを使用することがあります。

test.txtの

yes all work and no play makes Jack a dull boy | head -c 50M > test.txt 
echo "Jack is no fun" >> test.txt 
echo "Jack is no Fun" >> test.txt 

デモンストレーション

を作成します。

以下は、遅さのデモンストレーションです。 --ignore-caseオプションを追加すると、コマンドは57倍遅くなります。周りグーグル

$ time grep fun test.txt 
all work and no plJack is no fun 
real 0m0.061s 

$ time grep --ignore-case fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m3.498s 

可能な説明

私は、UTF-8ロケールでゆっくりしているのgrepについての議論を発見しました。だから私は次のテストを実行し、スピードアップしました。私のマシンのデフォルトのロケールはen_US.UTF-8なので、POSIXに設定するとパフォーマンスが向上したようですが、今はもちろん、望ましくないUnicodeテキストを正しく検索することができません。まだ2.5倍遅いです。

$ time LANG=POSIX grep --ignore-case fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.142s 

代替

我々は、それが5.5倍速く大文字と小文字の区別はgrepその後、まだ高速ですが、代わりにPerlを使用することができます。上記のPOSIX grepは約2倍高速です。

$ time perl -ne '/fun/i && print' test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.388s 

誰かがいる場合は、速い正しい代替案と説明を見つけたいと思います。

UPDATE - CentOSの

両方の上に試験した2台のマシンがUbuntuの1 11.04(ナッティイッカク)、その他12.04(精密センザンコウ)を実行しました。 CentOS 5.3マシンで同じテストを実行すると、以下の興味深い結果が得られます。 2つのケースのパフォーマンス結果はほぼ同じです。今CentOS 5.3が2009年1月にリリースされ、grep 2.5.1が実行され、Ubuntu 12.04がgrep 2.10を実行しています。したがって、新しいバージョンには変更があり、2つのディストリビューションの違いがあるかもしれません。

私はこのバグレポートは、それが遅い理由を理解するのに役立ちます考える
$ time grep fun test.txt 
Jack is no fun 
real 0m0.026s 

$ time grep --ignore-case fun test.txt 
Jack is no fun 
Jack is no Fun 
real 0m0.027s 

答えて

0

大文字と小文字を区別しない検索を実行するには、grepのは最初の1にあなたの全体の50  メガバイトのファイルを変換する必要がありケースまたはその他。それは時間がかかるでしょう。それだけでなく、メモリコピーがあります。

テストケースでは、まずファイルを生成します。これは、それがメモリにキャッシュされることを意味します。最初のgrepの実行は、キャッシュされたページをmmapにするだけです。ディスクにアクセスする必要はありません。

大文字と小文字を区別しないgrepは同じ処理を行いますが、そのデータを変更しようとします。これは、カーネルが修正された各4   kBページに対して例外をとることを意味し、50   MB全体を一度に1ページずつ新しいメモリにコピーしなければならなくなります。

基本的には、私はと考えています。これは遅いです。 57倍も遅くないかもしれませんが、確かに遅くなります。

+0

私はあなたがこれについて正しいとは思わない。このファイルはわずか50MBです。もっと重要なことに、私の更新を見て、centosはほぼ同じ実行時間で両方の検索を実行します。 –

+0

50MBは12500のメモリページ、MP3の50分、ホットメールの添付ファイルの制限の5倍です....私はそれを "小さな"と呼ぶのはわかりません。とにかく、私が言ったように – ams

+0

。 57倍の速度が少し過大に見えます。 – ams

8

この遅さは、「/ usr/lib/locale/locale-archive」と「/usr/lib/gconv/gconv-modules.cache」というファイルに絶えずアクセスしているためです(UTF-8ロケール上)。

これは、straceユーティリティを使用して表示できます。どちらのファイルもglibcからのものです。

+0

straceを使用する場合+1 –

0

なぜなら、現在のロケールではUnicode対応の比較を行い、Maratの答えで判断する必要があるからです。これはあまり効率的ではありません。

これは、Unicodeを考慮しない場合で、どれほど速い示しています、もちろん

$ time LC_CTYPE=C grep -i fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.192s 

、この代替案は、例えば、N/N、O/Oなどの他の言語の文字で動作しません。 Ð/ð、Æ/æなど。

もう一つの選択肢は、それはケース非感受性と一致するように正規表現を変更することです:

$ time grep '[Ff][Uu][Nn]' test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m0.193s 

これは合理的に高速ですが、もちろん、それはクラスに各文字を変換するための痛みだし、それが簡単ではありません上記とは異なり、エイリアスまたはshスクリプトに変換してください。比較のために

、私のシステムでは:

$ time grep fun test.txt 
all work and no plJack is no fun 
real 0m0.085s 

$ time grep -i fun test.txt 
all work and no plJack is no fun 
Jack is no Fun 
real 0m3.810s 
関連する問題