【问题标题】:Fastest possible grep最快的 grep
【发布时间】:2012-02-22 09:48:34
【问题描述】:

我想知道是否有任何提示可以让 grep 尽可能快。我有一个相当大的文本文件库,可以以最快的方式搜索。我将它们全部设为小写,这样我就可以摆脱-i 选项。这使搜索速度更快。

另外,我发现-F-P 模式比默认模式更快。当搜索字符串不是正则表达式(只是纯文本)时,我使用前者,如果涉及正则表达式,则使用后者。

有人有加速grep的经验吗?也许用一些特定的标志从头开始编译它(我在 Linux CentOS 上),以某种方式组织文件,或者以某种方式使搜索并行?

【问题讨论】:

  • 这总是同一组文件吗?如果您发现自己使用 grep 搜索相同的(大)文件集,也许是时候寻找正确索引它们的解决方案了(“最佳”解决方案将取决于这些文件的类型)。
  • 是的,它是同一组文件。你认为像 lucene 这样的全文解决方案会提高性能吗?一般来说,搜索 2500 个文件(每个文件是一本文学书籍)大约需要 30/40 秒,总字数约为 2.5 亿字。
  • "...or maybe make the search parallel in some way?" 听到这个消息我会非常兴奋。 grep 应该完全可以并行操作,但我怀疑搜索可能仍受 I/O 限制。
  • 您是否尝试过使用ack-grep

标签: bash unix grep


【解决方案1】:

试试GNU parallel,其中包括an example of how to use it with grep

grep -r 递归遍历目录。在多核 CPU 上 GNU parallel 通常可以加快速度。

find . -type f | parallel -k -j150% -n 1000 -m grep -H -n STRING {}

这将为每个核心运行 1.5 个作业,并为 grep 提供 1000 个参数。

对于大文件,它可以使用 --pipe--block 参数将输入分成几个块:

 parallel --pipe --block 2M grep foo < bigfile

您也可以通过 SSH 在几台不同的机器上运行它(需要 ssh-agent 来避免密码):

parallel --pipe --sshlogin server.example.com,server2.example.net grep foo < bigfile

【讨论】:

  • 使用 --color=always 保留 grep 颜色(在管道中使用 grep 时也是如此)
  • 如果find-print0 谓词(大多数都有),最好使用find . -type f -print0 | parallel -0 -k …。我的man(1) parallel 实例实际上是这样说的。另外,我怀疑globstar 如果您使用特定的文件模式,您可以更快地完成此操作:shopt -s globstar; parallel -k -j150% -n 1000 -m fgrep -H -n STRING ::: **/*.c
  • @WilliamPursell 如果您希望sudo 访问bigfile,这是cat 的有用用法
  • 为什么要设置每个核心 1.5 个作业?为什么不是每个核心 1 个工作?
  • @JohnGalt 通常磁盘 I/O 会停止其中一个进程。通过启动多于几个核心,所有核心仍然需要做一些事情——即使有一些工作正在等待数据。调整 150% 以查看最适合您系统的设置。
【解决方案2】:

严格来说不是代码改进,但在对 2+ 百万个文件运行 grep 后我发现这很有帮助。

我将操作转移到便宜的 SSD 驱动器 (120GB) 上。如果您经常处理大量文件,它的价格约为 100 美元,这是一个经济实惠的选择。

【讨论】:

    【解决方案3】:

    如果您要搜索非常大的文件,那么设置您的语言环境真的很有帮助。

    GNU grep 在 C 语言环境中比使用 UTF-8 快得多。

    export LC_ALL=C
    

    【讨论】:

    • 令人印象深刻,看起来这一行提供了 2 倍的速度。
    • 谁能解释这是为什么?
    • “简单字节比较与多字节字符比较”
    • 所以这并不完全安全,尤其是在您进行模式匹配(而不仅仅是字符串匹配)或文件内容不是 ascii 的情况下。在某些情况下仍然值得做,但要小心。
    • @RobertEMealey 他说的是“单一”而不是“简单”吗?
    【解决方案4】:

    显然使用 --mmap 可以帮助某些系统:

    http://lists.freebsd.org/pipermail/freebsd-current/2010-August/019310.html

    【讨论】:

      【解决方案5】:

      cgrep,如果可用的话,可以比 grep 快几个数量级。

      【讨论】:

        【解决方案6】:

        MCE 1.508 包括一个双块级 {file, list} 包装脚本,支持许多 C 二进制文件; agrep、grep、egrep、fgrep 和 tre-agrep。

        https://metacpan.org/source/MARIOROY/MCE-1.509/bin/mce_grep

        https://metacpan.org/release/MCE

        当想要 -i 快速运行时,不需要转换为小写。只需将 --lang=C 传递给 mce_grep。

        输出顺序被保留。 -n 和 -b 输出也是正确的。不幸的是,本页提到的 GNU 并行并非如此。我真的希望 GNU Parallel 能在这里工作。另外,mce_grep 在调用二进制文件时not sub-shell (sh -c /path/to/grep)。

        另一个替代方案是 MCE 中包含的 MCE::Grep 模块。

        【讨论】:

        • 作为上述工具的作者,您需要提供免责声明。
        【解决方案7】:

        基于 Sandro 的回复,我查看了他提供的参考资料here,并尝试了 BSD grep 与 GNU grep。我的快速基准测试结果显示:GNU grep 快得多。

        所以我对原始问题“最快的 grep”的建议:确保您使用的是 GNU grep 而不是 BSD grep(例如,这是 MacOS 上的默认设置)。

        【讨论】:

        • 在搜索 250 MB .sql 转储文件时,我在 13" MacBook Pro 上显示 BSD Grep 的速度比 8GB、6 核 Linode 更快。6 秒 vs 25 秒
        【解决方案8】:

        如果您不关心哪些文件包含该字符串,您可能希望将 readinggrepping 分成两个作业,因为生成 @ 可能成本很高987654321@ 多次 - 每个小文件一次。

        1. 如果你有一个非常大的文件:

          parallel -j100% --pipepart --block 100M -a &lt;very large SEEKABLE file&gt; grep &lt;...&gt;

        2. 许多小压缩文件(按inode排序)

          ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j80% --group "gzcat {}" | parallel -j50% --pipe --round-robin -u -N1000 grep &lt;..&gt;

        我通常使用 lz4 压缩文件以获得最大吞吐量。

        1. 如果您只想要匹配的文件名:

          ls -i | sort -n | cut -d' ' -f2 | fgrep \.gz | parallel -j100% --group "gzcat {} | grep -lq &lt;..&gt; &amp;&amp; echo {}

        【讨论】:

          【解决方案9】:

          我个人使用 ag(silver searcher)而不是 grep,它的速度更快,您也可以将它与并行和管道块结合使用。

          https://github.com/ggreer/the_silver_searcher

          更新: 我现在使用https://github.com/BurntSushi/ripgrep,这比 ag 更快,具体取决于您的用例。

          【讨论】:

          • 我发现了一个错误。有时它不会深入到树中,我遇到 grep 显示结果但 ag 没有的情况。我不能为了速度而牺牲准确性。
          • 您应该在他们的 github 帐户上打开一个问题并报告它(我会这样做,但我无法复制它),因为到目前为止我没有发现任何不准确之处。他们肯定会解决这个问题,是的,你是对的,我完全同意:准确性第一。
          【解决方案10】:

          我发现使用 grep 在单个大文件中搜索(尤其是更改模式)更快的一件事是使用 split + grep + xargs 和它的并行标志。例如:

          在名为 my_ids.txt 的大文件中拥有一个要搜索的 id 文件 大文件名 bigfile.txt

          使用 split 将文件拆分为多个部分:

          # Use split to split the file into x number of files, consider your big file
          # size and try to stay under 26 split files to keep the filenames 
          # easy from split (xa[a-z]), in my example I have 10 million rows in bigfile
          split -l 1000000 bigfile.txt
          # Produces output files named xa[a-t]
          
          # Now use split files + xargs to iterate and launch parallel greps with output
          for id in $(cat my_ids.txt) ; do ls xa* | xargs -n 1 -P 20 grep $id >> matches.txt ; done
          # Here you can tune your parallel greps with -P, in my case I am being greedy
          # Also be aware that there's no point in allocating more greps than x files
          

          就我而言,这将原本需要 17 小时的工作缩减为 1 小时 20 分钟的工作。我敢肯定这里有某种关于效率的钟形曲线,显然超过可用内核对你没有任何好处,但对于我的上述要求,这是一个比上述任何 cmets 更好的解决方案。与使用大多数(linux)本机工具的脚本并行相比,这有一个额外的好处。

          【讨论】:

            【解决方案11】:

            Ripgrep 声称现在是最快的。

            https://github.com/BurntSushi/ripgrep

            默认情况下还包括并行性

             -j, --threads ARG
                          The number of threads to use.  Defaults to the number of logical CPUs (capped at 6).  [default: 0]
            

            来自自述文件

            它建立在 Rust 的正则表达式引擎之上。 Rust 的正则表达式引擎使用 有限自动机、SIMD 和积极的文字优化 搜索速度非常快。

            【讨论】:

              【解决方案12】:

              与原始主题略有不同:来自 googlecodesearch 项目的索引搜索命令行实用程序比 grep 快得多:https://github.com/google/codesearch:

              一旦你编译它(需要golang 包),你可以索引一个文件夹:

              # index current folder
              cindex .
              

              索引将在~/.csearchindex下创建

              现在你可以搜索了:

              # search folders previously indexed with cindex
              csearch eggs
              

              我仍在通过 grep 管道传输结果以获得彩色匹配。

              【讨论】:

                猜你喜欢
                • 2018-12-15
                • 1970-01-01
                • 1970-01-01
                • 2014-10-08
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2012-07-14
                • 1970-01-01
                相关资源
                最近更新 更多