grep为何如此之快

下面是GNU grep的原作者MikeHaertel 在FreeBSD邮件列表中对 “GNU grep为什么比BSD grep要快” 这个问题所做的回答,解释了grep是如何进行快速搜索的,下面是邮件正文内容:

why GNU grep is fast

Mike Haertel mike at ducky.net

Sat Aug 21 03:00:30 UTC 2010

?     Previous message: Latest intr problems

?     Next message: why GNU grep is fast

?     Messages sorted by: [ date ] [ thread ] [subject ] [ author ]

________________________________________

Hi Gabor,

I am the original author of GNU grep.  I am also a FreeBSD user,

although I live on -stable (and older) andrarely pay attention

to -current.

However, while searching the -current mailinglist for an unrelated

reason, I stumbled across some flamageregarding BSD grep vs GNU grep

performance. You may have noticed that discussion too...

Anyway, just FYI, here‘s a quick summary ofwhere GNU grep gets

its speed. Hopefully you can carry these ideas over to BSD grep.

#1 trick: GNU grep is fast because it AVOIDSLOOKING AT

EVERY INPUT BYTE.

#2 trick: GNU grep is fast because itEXECUTES VERY FEW

INSTRUCTIONS FOR EACH BYTE that it *does*look at.

GNU grep uses the well-known Boyer-Moorealgorithm, which looks

first for the final letter of the targetstring, and uses a lookup

table to tell it how far ahead it can skip inthe input whenever

it finds a non-matching character.

GNU grep also unrolls the inner loop ofBoyer-Moore, and sets up

the Boyer-Moore delta table entries in such away that it doesn‘t

need to do the loop exit test at every unrolledstep.  The result

of this is that, in the limit, GNU grepaverages fewer than 3 x86

instructions executed for each input byte itactually looks at

(and it skips many bytes entirely).

See "Fast String Searching", byAndrew Hume and Daniel Sunday,

in the November 1991 issue of SoftwarePractice & Experience, for

a good discussion of Boyer-Mooreimplementation tricks.  It‘s

available as a free PDF online.

Once you have fast search, you‘ll find youalso need fast input.

GNU grep uses raw Unix input system calls andavoids copying data

after reading it.

Moreover, GNU grep AVOIDS BREAKING THE INPUTINTO LINES.  Looking

for newlines would slow grep down by a factorof several times,

because to find the newlines it would have tolook at every byte!

So instead of using line-oriented input, GNUgrep reads raw data into

a large buffer, searches the buffer usingBoyer-Moore, and only when

it finds a match does it go and look for thebounding newlines.

(Certain command line options like -n disablethis optimization.)

Finally, when I was last the maintainer ofGNU grep (15+ years ago...),

GNU grep also tried very hard to set thingsup so that the *kernel*

could ALSO avoid handling every byte of theinput, by using mmap()

instead of read() for file input.  At the time, using read() caused

most Unix versions to do extra copying.  Since GNU grep passed out

of my hands, it appears that use of mmapbecame non-default, but you

can still get it via --mmap.  And at least in cases where the data

is already file system buffer caches, mmap isstill faster:

$time sh -c ‘find . -type f -print | xargs grep -l 123456789abcdef‘

real     0m1.530s

user     0m0.230s

sys      0m1.357s

$time sh -c ‘find . -type f -print | xargs grep --mmap -l 123456789abcdef‘

real     0m1.201s

user     0m0.330s

sys      0m0.929s

[workload was a 648 megabyte MH mail foldercontaining 41000 messages]

So even nowadays, using --mmap can be worth a>20% speedup.

Summary:

- Use Boyer-Moore (and unroll its inner loopa few times).

- Roll your own unbuffered input using rawsystem calls.  Avoid copying

theinput bytes before searching them.  (Do,however, use buffered

*output*.  The normal grepscenario is that the amount of output is

smallcompared to the amount of input, so the overhead of output

buffer copying is small, while savings due to avoiding many small

unbuffered writes can be large.)

- Don‘t look for newlines in the input untilafter you‘ve found a match.

- Try to set things up (page-aligned buffers,page-sized read chunks,

optionally use mmap) so the kernel can ALSO avoid copying the bytes.

The key to making programs fast is to makethem do practically nothing. ;-)

Regards,

Mike

下面是翻译:

Gabor 您好,

我是GNU grep的原作者,同时我也是一名FreeBSD用户,不过我一直使用的是-stable版本(一个更老的版本),没怎么关注-current版本。

但是,当我无意间翻阅-current版的邮件列表时,发现了一些关于BSD grep与GNU grep性能的讨论,你可能也注意到了。

不管怎么说,仅供参考,下面是一些关于为什么GNU grep如此之快的简单总结。或许你能借鉴其中的一些思想运用到BSD grep中去。

#技巧1:GNU grep之所以快是因为它并不会去检查输入中的每一个字节

#技巧2:GNU grep之所以快是因为它对那些的确需要检查的每个字节都执行非常少的指令(操作)

GNU grep使用了非常著名的Boyer-Moore算法,该算法首先从目标字符串的最后一个字符开始查找,并且使用一个查找表,它可以在发现一个不匹配字符之后,计算出可以跳过多少个输入字符并继续查找。

GNU grep还展开了Boyer-Moore算法的内部循环,并建立了一个Boyer-Moore的delta表,这样它就不需要在每一个展开的步骤进行循环退出判断了。这样的结果就是,在极限情况下,GNU grep在需要检查的每一个输入字节上所执行的x86指令不会超过3条(并且还跳过了许多字节)。

你可以看看由Andrew Hume和Daniel Sunday 1991年11月在“Software Practice & Experience”上发表的论文“FastString Searching”,该文很好的讨论了Boyer-Moore算法的实现技巧,该文有免费的PDF在线版(这里查看或下载)。

一旦有了快速搜索,这时你会发现也需要同样快速的输入。

GNU grep使用了原生Unix输入系统调用并避免了在读取后对数据进行拷贝。

而且,GNU grep还避免了对输入进行分行,查找换行符会让grep减慢好几倍,因为要找换行符你就必须查看每个字节!

所以GNU grep没有使用基于行的输入,而是将原数据读入到一个大的缓冲区buffer,用Boyer-Moore算法对这个缓冲区进行搜索,只有在发现一个匹配之后才会去查找最近的换行符(某些命令参数,比如-n会禁止这种优化)。

最后,当我还在维护GNU grep的时候(15+年前……),GNU grep也尝试做一些非常困难的事情使内核也能避免处理输入的每个字节,比如使用mmap()而不是read()来进行文件输入。当时,用read()会使大部分Unix版本造成一些额外的拷贝。因为我已经不再GNU grep了,所以似乎mmap已经不再默认使用了,但是你仍然可以通过参数–mmap来启用它,至少在文件系统的buffer已经缓存了你的数据的情况下,mmap仍然要快一些:


1

2

3

4

5

6

7

8


$ time sh -c ‘find . -type f -print | xargs grep -l 123456789abcdef‘

real  0m1.530s

user  0m0.230s

sys   0m1.357s

$ time sh -c ‘find . -type f -print | xargs grep --mmap -l 123456789abcdef‘

real  0m1.201s

user  0m0.330s

sys   0m0.929s

[这里使用的输入是一个648M的MH邮件文件夹,包含大约41000条信息]

所以即使在今天,使用–mmap仍然可以提速20%以上。

总结:

- 使用Boyer-Moore算法(并且展开它的内层循环)。

- 使用原生系统调用来建立你的缓冲输入,避免在搜索之前拷贝输入字节。(无论如何,最好使用缓冲输出,因为在grep的常用场景中,输出的要比输入的少,所以输出缓冲拷贝的开销要小,并且可以节省许多这样小的无缓冲写操作。)

- 在找到一个匹配之前,不要查找换行符。

- 尝试做一些设置(比如页面对齐缓冲区,按页大小来读取块,选择性的使用mmap),这样可以使内核避免拷贝字节。

让程序变得更快的关键就是让它们做更少的事情。;-)

致礼

Mike

时间: 2024-10-09 22:14:55

grep为何如此之快的相关文章

shell三剑客之grep

前言 grep怎么出来的? 这就需要我们庖丁解牛了,"g/RE/p"看到没,就是这样"global Regular Expression print"==>"全局查找正则表达式(RE)并且打印结果行." grep家族由命令grep,egrep和fgrep组成.后两者是前者的变体.一个胖了,一个瘦了而已. 使用grep的好处就在于,不需要启动编辑器就可以执行查找操作,也用不着把pattern放在"//"里,使用grep要比

linux工具集

1.ag:比grep.ack更快的递归搜索文件内容 安装: 1:首先在linux创建个sh文件->ag.sh 2:在ag.sh里面输入如下内容并保存 set -x TEMP_DIR=$(mktemp -d Leslie.Guan.XXXXXX) cd ${TEMP_DIR} wget https://github.com/ggreer/the_silver_searcher/archive/master.zip TAR_DIR=$(unzip *.zip) TAR_DIR=${TAR_DIR%%

grep之字符串搜索算法Boyer-Moore由浅入深(比KMP快3-5倍)

这篇长文历时近两天终于完成了,前两天帮网站翻译一篇文章“为什么GNU grep如此之快?”,里面提及到grep速度快的一个重要原因是使用了Boyer-Moore算法作为字符串搜索算法,兴趣之下就想了解这个算法,发现这个算法一开始还挺难理解的,也许是我理解能力不是很好吧,花了小半天才看懂,看懂了过后就想分享下,因为觉得这个算法真的挺不错的,以前一直以为字符串搜索算法中KMP算很不错的了,没想到还有更好的,Boyer-Moore算法平均要比KMP快3-5倍. 下面是我对该算法的理解,参考了一些关于该

工具之grep

转自:http://www.cnblogs.com/dong008259/archive/2011/12/07/2279897.html grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. Unix的grep家族包括grep.egrep和fgrep.egrep和fgrep的命令只跟grep有很小不同.egr

Linux常用命令002之搜索命令locate、whereis、which、find、grep

-20150811 常用搜索命令 -------文件搜索命令---------- -->locate命令  --速度比find快 locate 文件名 在后台数据库中按文件名搜索,搜索速度更快 /var/lib/mlocate #locate命令所搜索的后台数据库 updatedb命令 --新建的文件用locate命令搜索不到,更新数据库后可以 --可以手动更新数据库 updatedb 缺点:只能按照文件名搜索 --------命令搜索命令---------- -->whereis 命令 wh

grep 和vim用法

grep :文本过滤( 模式:pattern) 工具 包括:grep, egrep, fgrep (不 支持正则表达式 搜索) 用法格式: grep [OPTIONS] PATTERN [FILE-] 模式:由正则表达式字符及文本字符所编写的过滤条件 各种选项:  –color=auto :     显示匹配的文本着色,centos7已经自动匹配红色 -b              :     显示不被模式匹配的行 -i     :忽略字符大小写                -n   :  显

liunx 的 grep命令(转载)

简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. grep常用用法 [[email protected] ~]# grep [-acinv] [--color=auto] '搜寻字符串' filename 选项与参数: -a :将 binary 文件以 text 文件的方式搜寻数据 -c :计算找到

Linux 命令——grep | 正则表达式

感觉讲的很详细,瞬间懂了grep,正则. from: here 简介 grep (global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来. Unix的grep家族包括grep.egrep和fgrep.egrep和fgrep的命令只跟grep有很小不同.egrep是grep的扩展,支持更多的re元字符, fgrep就是fixe

Dnsmasq安装与配置-搭建本地DNS服务器 更干净更快无广告DNS解析

默认的情况下,我们平时上网用的本地DNS服务器都是使用电信或者联通的,但是这样也导致了不少的问题,首当其冲的就是上网时经常莫名地弹出广告,或者莫名的流量被消耗掉导致网速变慢.其次是部分网站域名不能正常被解析,莫名其妙地打不开,或者时好时坏. 如果碰上不稳定的本地DNS,还可能经常出现无法解析的情况.除了要避免"坏"的DNS的影响,我们还可以利用DNS做些"好"事,例如管理局域网的DNS.给手机App Store加速.纠正错误的DNS解析记录.保证上网更加安全.去掉网