grep如何运行如此之快?
我对shell中的GREP的function感到非常惊讶,之前我曾经在java中使用子string方法,但现在我使用GREP,它在几秒钟内执行,比我以前编写的java代码快得多。 (根据我的经验,虽然我可能是错的)
这是说,我一直无法弄清楚它是如何发生的? 网上也没有太多可用的东西。
谁能帮我这个?
假设你的问题专门针对GNU grep
。 以下是作者Mike Haertel的一段话:
GNU grep是快速的,因为它避免每个input字节。
GNU grep是快速的,因为它执行每个BYTE的很多指令,它看起来。
GNU grep使用了着名的Boyer-Moorealgorithm,该algorithm首先查找目标string的最后一个字母,然后使用查找表来告诉它在find不匹配的字符时可以在input中跳过多远。
GNU grep也展开了Boyer-Moore的内部循环,并且设置了Boyer-Moore增量表的条目,使得它不需要在每个展开的步骤中进行循环出口testing。 这样做的结果是,在极限情况下,GNU grep平均每个input字节执行的平均指令less于3个x86指令(它完全忽略了许多字节)。
GNU grep使用原始的Unixinput系统调用,并在读取数据后避免复制数据。 而且,GNU grep AVOIDS打破了input到行。 寻找换行符会使grep下降几倍,因为要find新行就必须查看每个字节!
因此,GNU grep不是使用面向行的input,而是将原始数据读取到一个大的缓冲区中,使用Boyer-Mooresearch缓冲区,只有当它find匹配时才会去寻找边界换行符(某些命令行选项 – 禁用此优化。)
这个答案是从这里取得的信息的一个子集。
添加到史蒂夫的优秀答案。
它可能并不广为人知,但grep几乎总是比较短的格式string更快 ,因为在更长的模式中, Boyer-Moore可以更长的跳跃前进,以达到更好的次线速度:
例:
# 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
更长的forms是35%更快!
怎么来的? Boyer-Moore从模式string构造了一个跳转表,每当出现不匹配的时候,在比较input中的单个字符到跳转表中的字符之前,它会select最长的跳转(从最后一个字符到最后一个字符)。
这是一个很好的video解释博伊尔摩尔
另一个常见的误解(对于GNU grep)是fgrep
比grep
快。 fgrep
中的f
不代表'fast',代表'fixed'(参见手册页),并且由于两者都是相同的程序,并且都使用Boyer-Moore ,所以在search时它们之间的速度没有区别没有正则expression式特殊字符的固定string。 我使用fgrep
的唯一原因是有一个正则expression式特殊字符(如.
, []
或*
),我不希望它被解释为这样。 即使如此,更可移植/标准forms的grep -F
比fgrep
更fgrep
。