【问题标题】:How do I grep in parallel我如何并行grep
【发布时间】:2012-08-10 09:33:48
【问题描述】:

我通常使用grep -rIn pattern_str big_source_code_dir 来查找一些东西。但grep 不平行,我该如何让它平行?我的系统有4个核心,如果grep可以使用所有核心,那就更快了。

【问题讨论】:

标签: linux grep


【解决方案1】:

GNU parallel 命令对此非常有用。

sudo apt-get install parallel # if not available on debian based systems

然后,paralell 手册页提供了一个示例:

EXAMPLE: Parallel grep
       grep -r greps recursively through directories. 
       On multicore CPUs GNU parallel can often speed this up.

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

       This will run 1.5 job per core, and give 1000 arguments to grep.

你的情况可能是:

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

最后,GNU 并行手册页还提供了描述 xargsparallel 命令之间差异的部分,这应该有助于理解为什么并行在您的情况下看起来更好

DIFFERENCES BETWEEN xargs AND GNU Parallel
       xargs offer some of the same possibilities as GNU parallel.

       xargs deals badly with special characters (such as space, ' and "). To see the problem try this:

         touch important_file
         touch 'not important_file'
         ls not* | xargs rm
         mkdir -p "My brother's 12\" records"
         ls | xargs rmdir

       You can specify -0 or -d "\n", but many input generators are not optimized for using NUL as separator but are optimized for newline as separator. E.g head, tail, awk, ls, echo, sed, tar -v, perl (-0 and \0 instead of \n),
       locate (requires using -0), find (requires using -print0), grep (requires user to use -z or -Z), sort (requires using -z).

       So GNU parallel's newline separation can be emulated with:

       cat | xargs -d "\n" -n1 command

       xargs can run a given number of jobs in parallel, but has no support for running number-of-cpu-cores jobs in parallel.

       xargs has no support for grouping the output, therefore output may run together, e.g. the first half of a line is from one process and the last half of the line is from another process. The example Parallel grep cannot be
       done reliably with xargs because of this.
       ...

【讨论】:

  • 我不同意。 grepping 时,您的限制因素是 IO 吞吐量,而不是 CPU 时间。在问题上投入更多核心不会使您的磁盘旋转得更快。
  • 我不同意你的不同意:#time grep -E 'invalid user (\S+) from ([0-9]+\.[0-9]+\.[0-9]+ \. [0-9]+) port ([0-9]+)' /var/log/auth.log 在我的 i7 上显示 10 秒 然后测试驱动器的速度:# dd if=/var/log/auth. log of=/dev/null bs=1M 以 130MB/s 的速度为 600MB 提供 4 秒但上面的 grep 需要 3 多时间,接近 40MB/秒来读取数据。所以,这里正则表达式的处理时间是最广泛的并行运行:parallel --pipe --block 16M grep -E 'invalid user (\S+) from ([0-9]+\.[0-9]+ \.[0-9]+\.[0-9]+) 端口 ([0-9]+)' /log/auth.log 用 3 秒代替 10...
  • 这似乎是最好的答案,为什么不是更高? O_o
  • 啊 - 因为它不起作用.. 幸运的是我能够使用 comm 来解决我的特定问题,在相同情况下它比 grep 快得多..
  • 并行 grep 对于高延迟的网络挂载会很方便。
【解决方案2】:

请注意,您需要对并行 grep 搜索词中的特殊字符进行转义,例如:

parallel --pipe --block 10M --ungroup LC_ALL=C grep -F 'PostTypeId=\"1\"' < ~/Downloads/Posts.xml > questions.xml

使用独立的 grep,grep -F 'PostTypeId="1"' 可以在不转义双引号的情况下工作。我花了一段时间才弄明白!

还要注意使用LC_ALL=C-F 标志(如果您只是搜索完整的字符串)以获得额外的加速。

【讨论】:

    【解决方案3】:

    如果您使用 HDD 来存储您正在搜索的目录,则不会提高速度。硬盘驱动器几乎是单线程访问单元。

    但如果你真的想做并行 grep,那么 this website 给出了两个提示,告诉你如何使用 findxargs 来做这件事。例如

    find . -type f -print0 | xargs -0 -P 4 -n 40 grep -i foobar
    

    【讨论】:

    • 我从源网站复制了错误的示例,抱歉。我会修复答案。
    • 请注意,使用 xargs 您可能会遇到混合输出的风险。要查看此操作,请参阅:gnu.org/software/parallel/…
    • 在同一目录树上重复 grep 时,并行 grep 的好处会很明显,例如,对于同一源代码中的不同关键字。文件内容将缓存在 RAM 中(当然,这取决于您拥有多少 RAM 和源代码)。
    【解决方案4】:

    这里有 3 种方法可以做到这一点,但您无法获得其中两种方法的行号。

    (1) 对多个文件并行运行 grep,在这种情况下是一个目录及其子目录中的所有文件。添加 /dev/null 以强制 grep 将文件名添加到匹配行,因为您会想知道匹配的文件。为您的机器调整-P 的进程数。

    find . -type f | xargs -n 1 -P 4 grep -n <grep-args> /dev/null
    

    (2) 对多个文件串行运行 grep,但并行处理 10M 块。调整您的机器和文件的块大小。这里有两种方法可以做到这一点。

    # for-loop
    for filename in `find . -type f`
    do 
      parallel --pipepart --block 10M -a $filename -k "grep <grep-args> | awk -v OFS=: '{print \"$filename\",\$0}'"
    done
    
    # using xargs
    find . -type f | xargs -I filename parallel --pipepart --block 10M -a filename -k "grep <grep-args> | awk -v OFS=: '{print \"filename\",\$0}'"
    

    (3) 结合(1)和(2):对多个文件并行运行grep,并以块的形式并行处理它们的内容。为您的机器调整块大小和 xargs 并行度。

    find . -type f | xargs -n 1 -P 4 -I filename parallel --pipepart --block 10M -a filename -k "grep <grep-args> | awk -v OFS=: '{print \"filename\",\$0}'"
    

    请注意,(3) 可能不是资源的最佳利用方式。

    我有一个longer write-up,但这是基本概念。

    【讨论】:

      猜你喜欢
      • 2013-02-03
      • 2012-04-05
      • 1970-01-01
      • 2015-04-16
      • 1970-01-01
      • 2021-01-16
      • 2017-05-30
      • 2019-09-10
      • 2020-03-14
      相关资源
      最近更新 更多