GNU 并行:从起始目录开始为整个树的每个节点(目录和子*目录)分配一个线程

5 parallel-processing tree multithreading find gnu-parallel

我希望受益于parallelmacOS 上命令的所有潜力(似乎存在 2 个版本,GNU 和 Ole Tange 的版本,但我不确定)。

使用以下命令:

parallel -j8  find {} ::: *
Run Code Online (Sandbox Code Playgroud)

如果我位于包含8个子目录的目录中,我会有很大的性能。但是,如果所有这些子目录除了只有一个之外都具有较小的内容,那么我将只有一个线程可以在唯一的“大”目录上工作。

  1. 有没有办法遵循这个“大目录”的并行化?我的意思是,剩下的唯一线程可以得到其他线程的帮助吗(之前的线程适用于小子目录)?

    find理想的情况是,当上面的命令行中的命令找到所有小子时,并行命令“自动切换” 。也许是我问得太多了?

  2. 另一个潜在的优化(如果存在):考虑公共树目录结构:是否有一种类似于命令的方法make -j8,将每个当前线程分配给子(sub-(sub-....))))目录一旦探索了当前目录(别忘了,我主要想在findLinux 命令中使用这种优化),另一个线程探索另一个目录 sub-(sub-(sub- ....)))) 目录?

    当然,运行的总线程数不大于parallel命令指定的数量(parallel -j8在我上面的示例中):我们可以说,如果树元素的数量(1个节点=1个目录)大于线程数,我们不能超过这个数字。

    我知道在递归上下文中并行化很棘手,但当我想在大树结构中查找文件时,也许我可以获得一个重要因素?

    这就是为什么我以 command 为例make -j8:我不知道它是如何编码的,但这让我认为我们可以对parallel/find帖子开头的几个命令行执行相同的操作。

最后,我想得到您关于这两个问题的建议,更一般地说,目前这些优化建议什么是可能的,什么是不可能的,以便使用经典find命令更快地找到文件。

更新1:正如@OleTange所说,我不知道我想要gupdatedb索引的内容的先验目录结构。因此,很难提前知道maxdepth。您的解决方案很有趣,但第一次执行find不是多线程的,您不使用parallel命令。gupdatedb我有点惊讶的是,不存在多线程版本:在纸面上,这是可行的,但一旦我们想在gupdatedbMacOS 10.15 的 GNU 脚本中对其进行编码,那就更困难了。

如果有人有其他建议,我会接受!

Ole*_*nge 2

如果要并行化,find您需要确保您的磁盘可以传输数据。

对于磁驱动器,您很少会看到加速。有时用于 RAID、网络驱动器和 SSD,经常用于 NVMe。

最简单的并行化方法find是使用*/*

parallel find ::: */*
Run Code Online (Sandbox Code Playgroud)

或者*/*/*

parallel find ::: */*/*
Run Code Online (Sandbox Code Playgroud)

这将在子子目录和子子子目录中搜索。

他们不会搜索顶级目录,但这可以通过使用find适当的-maxdepth.

上述解决方案假设您对目录结构有所了解,因此它不是通用解决方案。

我从未听说过通用解决方案。它将涉及广度优先搜索,该搜索将并行启动一些工作人员。我可以看到它是如何编程的,但我从未见过它。

如果我要实现它,它会是这样的(经过轻微测试):

#!/bin/bash

tmp=$(tempfile)
myfind() {
  find "$1" -mindepth 1 -maxdepth 1
}
export -f myfind
myfind . | tee $tmp
while [ -s $tmp ] ; do
    tmp2=$(tempfile)
    cat $tmp | parallel --lb myfind | tee $tmp2
    mv $tmp2 $tmp
done
rm $tmp
Run Code Online (Sandbox Code Playgroud)

(PS:我有理由相信Ole Tange写的并行和GNU Parallel是一回事)。