为什么GNU grep速度很快?

2020-07-23 11:29:07

Mike Haertel Mike at ducky.net(世界标准时间2010年8月21日星期六03:00:30)嗨,我是GNU GREP的原始作者。我也是一名FreeBSD用户,虽然我的生活很稳定(年龄更大),很少关注当前的情况,但在搜索-current邮件列表时,出于无关的原因,我无意中发现了一些关于BSD grep与GNU grepperformance的争论。你可能也注意到了那个讨论……不管怎样,仅供参考,这里是GNU GREP获得速度的快速摘要。希望您能将这些想法带到BSD grep中。#1技巧:GNU grep速度很快,因为它避免了查找ATEVERY输入字节。#2技巧:GNU grep速度很快,因为它对它*确实*查看的每个字节执行非常快的FEWINSTRUCTIONS。GNU grep使用众所周知的Boyer-Moore算法,该算法首先查找目标字符串的最后一个字母,然后使用可查找表来告诉它可以领先多远。在每个展开的步骤都需要进行环路退出测试。其结果是,在限制中,GNU grep对于它实际查看的每个输入字节平均执行的指令少于3x86条(并且它完全跳过了许多字节)。有关Boyer-Moore实现技巧的详细讨论,请参阅Andrew Hume和Daniel SUNDAY在1991年11月刊的Software Practice&;Experience中所著的Fast String Search。它可以作为免费的PDF在线保存。一旦您拥有FAST Search,您会发现您还需要快速输入。GNU GREP使用原始的Unix输入系统调用,并避免在读取数据后复制数据。此外,GNU GREP避免将输入拆分成行。查找新行将使grep减慢数倍,因为要找到新行,它必须查看每个字节!因此,GNU grep不使用面向行的输入,而是将原始数据读入大缓冲区,使用Boyer-Moore搜索缓冲区,只有在找到匹配项时,它才会继续查找绑定的新行。(某些命令行选项,如-n禁用了这种优化。)最后,当我上一次担任GNU grep(15年前)的维护人员时。使用mmap()代替read()进行文件输入。当时,使用read()会导致大多数Unix版本执行额外的复制。自从GNU grep从我手中消失后,mmap的使用似乎变成了非默认的,但是您仍然可以通过--mmap获得它。而且,至少在数据已经在文件系统缓冲区缓存的情况下,mmap会更快:$time sh-c&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用户0m0.330s sys 0m0.929s[工作负载是包含41000封邮件的648MB MH邮件文件夹]因此,即使在今天,使用--mmap也可以获得20%的加速。摘要:--使用boyer-moore(并展开其内部循环几次)。-无缓冲滚动您自己的邮件文件夹。在搜索之前避免复制输入字节。(不过,一定要使用缓冲*输出*。正常的grep方案是,与输入量相比,输出量很小,因此输出缓冲区复制的开销很小,而由于避免了许多小型无缓冲写入而节省的成本可能会很大。)-在找到匹配项之前,不要在输入中查找换行符。-尝试进行设置(页面对齐的缓冲区、页面大小的读取区块,也可以使用mmap),以便内核也可以避免复制字节。使程序快速运行的关键是使它们变得更快。-尝试进行设置(页面对齐的缓冲区、页面大小的读取区块,也可以使用mmap),以便内核也可以避免复制字节。使程序变得快速的关键是使它们变得更快。(-)你好,迈克