具有并行处理功能的更好的 Unix 查找?

PP.*_*PP. 52 unix find

unixfind(1)实用程序非常有用,它允许我对符合特定规范的许多文件执行操作,例如

find /dump -type f -name '*.xml' -exec java -jar ProcessFile.jar {} \;
Run Code Online (Sandbox Code Playgroud)

上面的代码可能会对特定目录中的每个 XML 文件运行脚本或工具。

假设我的脚本/程序占用了大量 CPU 时间并且我有 8 个处理器。一次处理最多 8 个文件会很好。

GNU make 允许使用-j标志进行并行作业处理,但find似乎没有这样的功能。是否有替代的通用作业调度方法来解决这个问题?

Gai*_*ius 74

xargs带有-P选项(进程数)。假设我想压缩 4-cpu 机器上目录中的所有日志文件:

find . -name '*.log' -mtime +3 -print0 | xargs -0 -P 4 bzip2
Run Code Online (Sandbox Code Playgroud)

您还可以说-n <number>每个进程的最大工作单元数。所以说我有 2500 个文件,我说:

find . -name '*.log' -mtime +3 -print0 | xargs -0 -n 500 -P 4 bzip2
Run Code Online (Sandbox Code Playgroud)

这将启动 4 个bzip2进程,每个进程有 500 个文件,然后当第一个进程完成时,将启动最后 500 个文件的另一个进程。

不知道为什么前面的答案使用xargs and make,那里有两个并行引擎!

  • 使用 find/xargs,要小心:find 默认使用换行符作为输出分隔符,但 xargs 默认使用任何空格作为输入分隔符。在两者上使用 -0 以确保安全,或者切换到 GNU 并行,默认为换行符作为输入分隔符(匹配 find 的输出)。 (9认同)
  • 小心使用“xargs -P” - 它有一个从未修复的错误,每当两个线程碰巧在同一时刻产生输出时,它就会混淆输出(与“并行”不同)...... (2认同)

eph*_*ent 45

GNU 并行也可以提供帮助。

find /dump -type f -name '*.xml' | parallel -j8 java -jar ProcessFile.jar {}
Run Code Online (Sandbox Code Playgroud)

请注意,如果没有-j8参数,则parallel默认为您机器上的内核数:-)


Aln*_*tak 7

无需“修复” find——利用make自身来处理并行性。

让您的进程创建一个日志文件或其他一些输出文件,然后使用像这样的 Makefile:

.SUFFIXES:  .xml .out

.xml.out:
        java -jar ProcessFile.jar $< 1> $@
Run Code Online (Sandbox Code Playgroud)

并因此调用:

find /dump -type f -name '*.xml' | sed -e 's/\.xml$/.out/' | xargs make -j8
Run Code Online (Sandbox Code Playgroud)

更好的是,如果您确保仅在 Java 进程成功完成后才创建输出文件,您可以利用make的依赖处理来确保下次只完成未处理的文件。

  • 希望这些文件名中没有空格或其他“有趣”的字符;Make 不能很好地处理这些。 (2认同)

小智 5

Find 有一个并行选项,您可以直接使用“+”符号来使用;不需要 xargs。将它与 grep 结合起来,它可以快速地遍历你的树来寻找匹配项。例如,如果我正在查找源目录中包含字符串“foo”的所有文件,我可以调用
find sources -type f -exec grep -H foo {} +

  • 阅读 find 手册,您可以看到 `-exec command +` 语法并不是并行运行它,而是将许多文件“分组”在一起,并同时以多个文件作为参数运行该命令。碰巧 grep 可以并行地查看其目标。 (21认同)