15

--ignore-caseこのオプションを追加するgrepと、検索が 50 倍遅くなる可能性があることに非常に驚きました。これを 2 台の異なるマシンでテストしましたが、結果は同じでした。大きなパフォーマンスの違いの説明を知りたいです。

大文字と小文字を区別しない検索用の grep の代替コマンドも見たいと思います。正規表現は必要ありません。文字列検索を修正するだけです。まず、テスト ファイルはダミー データを含む 50 MB のプレーン テキスト ファイルで、次のコードを使用して生成できます。

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

代替案

代わりに Perl を使用することもできますが、それでも大文字と小文字を区別する grep よりも 5.5 倍高速です。また、上記の 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

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

更新 - CentOS

上記でテストされた 2 台のマシンは、Ubuntu 11.04 (Natty Narwhal) と 12.04 (Precise Pangolin) を実行していました。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
4

4 に答える 4

8

この遅さは、(UTF-8 ロケールでの) grep がファイル "/usr/lib/locale/locale-archive" および "/usr/lib/gconv/gconv-modules.cache" に常にアクセスするためです。

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

于 2013-01-09T13:44:47.207 に答える
8

このバグレポートは、遅い理由を理解するのに役立つと思います:

バグ レポート grep、ignore-case で遅い

于 2012-12-11T12:01:16.103 に答える
1

その理由は、現在のロケールに対して 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

もちろん、この代替方法は、Ñ/ñ、Ø/ø、Ð/ð、Æ/æ などの他の言語の文字では機能しません。

もう 1 つの方法は、大文字と小文字を区別しないように正規表現を変更することです。

$ 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
于 2016-11-25T18:16:15.660 に答える
0

大文字と小文字を区別しない検索を行うには、grep は最初に 50 MB のファイル全体を大文字または小文字に変換する必要があります。それには時間がかかります。それだけでなく、記憶のコピーもある...

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

大文字と小文字を区別しない grep も同じことを行いますが、そのデータを変更しようとします。これは、カーネルが変更された 4 kB ページごとに例外を取得し、一度に 1 ページずつ、50 MB 全体を新しいメモリにコピーする必要があることを意味します。

基本的に、これは遅くなると思います。57 倍遅くはないかもしれませんが、確実に遅くなります。

于 2012-12-11T12:12:02.260 に答える