如何使用 parallel 命令在我的 MacBook 上利用多核并行性?
How can I use the parallel command to exploit multi-core parallelism on my MacBook?
我经常在 Linux 和 macOS 上使用 find
命令。我刚刚发现命令 parallel
,如果可能的话,我想将它与 find
命令结合使用,因为当我们在大目录中搜索特定文件时,find
命令需要很长时间。
我已经搜索过此信息,但结果不够准确。似乎有很多可能的语法,但我不知道哪个是相关的。
如何将 parallel
命令与 find
命令(或任何其他命令)结合使用,以便从我的 MacBook 上的所有 16 个内核中获益?
更新
从@OleTange
开始,我想我找到了我感兴趣的那种命令。
所以,要了解更多关于这些命令的信息,我想知道字符 {}
和 :::
在以下命令中的用处:
parallel -j8 find {} ::: *
1) 这些字符是强制性的吗?
2) 如何插入 find
命令的经典选项,如 -type f
或 -name '*.txt
?
3) 目前我在 .zshrc
中定义了函数:
ff () {
find -type f -iname 2> /dev/null
}
如何用固定数量的工作做同样的事情(我也可以将其设置为 shell 参数)?
只需在每个一级路径分别使用背景运行
下面的例子将创建12个子目录分析
$ for i in [A-Z]*/ ; do find "$i" -name "*.ogg" & >> logfile ; done
[1] 16945
[2] 16946
[3] 16947
# many lines
[1] Done find "$i" -name "*.ogg"
[2] Done find "$i" -name "*.ogg"
#many lines
[11] Done find "$i" -name "*.ogg"
[12] Done find "$i" -name "*.ogg"
$
这样做会创建许多查找进程,系统将像其他进程一样在不同的内核上分派。
注意 1:这样做看起来有点笨拙,但确实有效..
注意 2: find
命令本身并没有对 cpus/cores 施加影响,这只是 99% 的用例没用,因为查找过程将花费时间等待来自磁盘的 I/O。然后使用并行或类似命令将不起作用*
当您的工作是 CPU bound (the CPU does the work, and the peripherals are mostly idle) but here, you are trying to improve the performance of a task which is I/O bound 时(CPU 大部分时间空闲,等待繁忙的外围设备),并行处理是有意义的。在这种情况下,增加并行性只会增加拥塞,因为多个任务将争夺它们之间已经很紧迫的 I/O 带宽。
在 macOS 上,系统已经为您的所有数据编制了索引(包括文字处理文档、PDF、电子邮件等的内容);在右上角的菜单栏上有一个友好的放大镜,您可以在其中访问更快、更通用的搜索,称为 Spotlight。 (虽然我同意 find
缺少一些更复杂的控件;而且“用户友好”的设计在它猜我想要的东西时妨碍了我,但猜错了。)
一些 Linux 发行版提供了类似的功能;我希望这会成为如今带有 GUI 的任何东西的标准,尽管细节会因系统而异。
任何类 Unix 系统上更传统的解决方案是 locate
命令,它执行类似但更有限的任务;它将在文件名上创建一个(非常活泼的)索引,所以你可以说
locate fnord
非常快速地获取名称匹配 fnord
的每个文件。该索引只是昨晚 find
运行 结果的副本(或者您将后端安排为 运行)。该命令已安装在 macOS 上,但如果要使用它,则必须启用后端。 (只需 运行 locate locate
即可获得进一步说明。)
例如,如果您发现自己经常寻找具有特定权限集和特定所有者的文件(这些不是 locate
记录的功能),您可以自己构建类似的东西;只是 运行 每晚(或每小时等)find
将这些特征收集到数据库中——甚至只是一个文本文件——然后你几乎可以立即搜索它。
对于 运行 并行作业,您实际上并不需要 GNU parallel
,尽管它确实为许多用例提供了许多便利和增强功能;您已经 xargs -P
。 (源自 BSD 的 macOS 上的 xargs
比 GNU xargs
更受限制,这是你会在许多 Linuxes 上找到的东西;但它确实有 -P
选项.)
例如,这里是 运行 八个并行 find
实例 xargs -P
:
printf '%s\n' */ | xargs -I {} -P 8 find {} -name '*.ogg'
(假设通配符不匹配包含单引号或换行符或其他恶作剧的目录;GNU xargs
有 -0
选项来修复大量类似的极端情况;那么您将使用 '%s[=32=]'
作为 printf
的格式字符串。)
正如 the parallel
documentation 所解释的那样,它的一般语法是
parallel -options command ...
其中 {}
将替换为当前输入行(如果缺少,将在 command ...
末尾隐式添加)和(显然可选):::
特殊标记允许您在命令行上指定输入源而不是标准输入。
这些特殊标记之外的任何内容都会逐字传递,因此您可以添加 find
选项,只需按字面说明即可。
parallel -j8 find {} -type f -name '*.ogg' ::: */
我不会说话 zsh
但重构为常规 POSIX sh
你的函数可能类似于
ff () {
parallel -j8 find {} -type f -iname "" ::: ""
}
尽管我可能会切换参数以便您可以指定名称模式和要搜索的文件列表,à la grep
.
ff () {
# "local" is not POSIX but works in many sh versions
local pat=
shift
parallel -j8 find {} -type f -iname "$pat" ::: "$@"
}
但再次强调,旋转磁盘以查找已编入索引的内容可能是您应该停止做的事情,而不是促进。
正如其他人所写的那样,find
I/O 很重,很可能不受您的 CPU 限制。
但是根据您的磁盘,可以更好地 运行 并行作业。
NVMe 磁盘以在并行访问 运行 4-8 次时性能最佳而著称。一些网络文件系统还可以更快地处理多个进程。
所以一定程度的并行化是有意义的,但您确实必须进行测量才能确定。
并行化 find
8 个作业 运行ning 并行:
parallel -j8 find {} ::: *
如果你在一个有很多子目录的目录中,这种方法效果最好:然后将并行搜索每个子目录。否则这可能会更好:
parallel -j8 find {} ::: */*
基本相同的想法,但现在使用目录的子目录。
如果您希望在找到结果后立即打印结果(而不是在 find
完成后),请使用 --line-buffer
(或 --lb
):
parallel --lb -j8 find {} ::: */*
要了解 GNU Parallel,请花 20 分钟阅读 https://doi.org/10.5281/zenodo.1146014 and print the cheat sheet: https://www.gnu.org/software/parallel/parallel_cheat.pdf
的第 1+2 章
你的命令行会感谢你的。
您似乎希望能够在 macOS 下的大目录中快速定位文件。我认为该工作的正确工具是 mdfind
.
我在我的主目录下创建了一个包含 10,000,000 个文件的层次结构,所有文件都具有类似于 UUID 的唯一名称,例如80104d18-74c9-4803-af51-9162856bf90d
。然后我试图找到一个:
mdfind -onlyin ~ -name 80104d18-74c9-4803-af51-9162856bf90d
结果是即时的,而且速度太快,无法测量时间,所以我进行了 100 次查找,用时不到 20 秒,所以平均一次查找需要 0.2 秒。
如果您真的想查找 100 个文件,您可以像这样将它们分组到一个搜索中:
mdfind -onlyin ~ 'kMDItemDisplayName==ffff4bbd-897d-4768-99c9-d8434d873bd8 || kMDItemDisplayName==800e8b37-1f22-4c7b-ba5c-f1d1040ac736 || kMDItemDisplayName==800e8b37-1f22-4c7b-ba5c-f1d1040ac736'
而且执行速度更快。
如果您只知道部分文件名,您可以使用:
mdfind -onlyin ~ "kMDItemDisplayName = '*cdd90b5ef351*'"
/Users/mark/Whosebug/MassiveDirectory/800f0058-4021-4f2d-8f5c-cdd90b5ef351
您还可以在搜索中使用创建日期、文件类型、作者、视频持续时间或标签。例如,您可以像这样查找名称包含“25DD954D73AF”的所有 PNG 图片:
mdfind -onlyin ~ "kMDItemKind = 'PNG image' && kMDItemDisplayName = '*25DD954D73AF*'"
/Users/mark/Whosebug/MassiveDirectory/9A91A1C4-C8BF-467E-954E-25DD954D73AF.png
如果您想知道可以搜索哪些字段,请获取您希望能够查找的类型的文件,然后 运行 mdls
在上面,您将看到所有macOS 知道的字段:
mdls SomeMusic.m4a
mdls SomeVideo.avi
mdls SomeMS-WordDocument.doc
更多示例here。
此外,与 locate
不同的是,不需要经常更新数据库。
我经常在 Linux 和 macOS 上使用 find
命令。我刚刚发现命令 parallel
,如果可能的话,我想将它与 find
命令结合使用,因为当我们在大目录中搜索特定文件时,find
命令需要很长时间。
我已经搜索过此信息,但结果不够准确。似乎有很多可能的语法,但我不知道哪个是相关的。
如何将 parallel
命令与 find
命令(或任何其他命令)结合使用,以便从我的 MacBook 上的所有 16 个内核中获益?
更新
从@OleTange
开始,我想我找到了我感兴趣的那种命令。
所以,要了解更多关于这些命令的信息,我想知道字符 {}
和 :::
在以下命令中的用处:
parallel -j8 find {} ::: *
1) 这些字符是强制性的吗?
2) 如何插入 find
命令的经典选项,如 -type f
或 -name '*.txt
?
3) 目前我在 .zshrc
中定义了函数:
ff () {
find -type f -iname 2> /dev/null
}
如何用固定数量的工作做同样的事情(我也可以将其设置为 shell 参数)?
只需在每个一级路径分别使用背景运行
下面的例子将创建12个子目录分析
$ for i in [A-Z]*/ ; do find "$i" -name "*.ogg" & >> logfile ; done
[1] 16945
[2] 16946
[3] 16947
# many lines
[1] Done find "$i" -name "*.ogg"
[2] Done find "$i" -name "*.ogg"
#many lines
[11] Done find "$i" -name "*.ogg"
[12] Done find "$i" -name "*.ogg"
$
这样做会创建许多查找进程,系统将像其他进程一样在不同的内核上分派。
注意 1:这样做看起来有点笨拙,但确实有效..
注意 2: find
命令本身并没有对 cpus/cores 施加影响,这只是 99% 的用例没用,因为查找过程将花费时间等待来自磁盘的 I/O。然后使用并行或类似命令将不起作用*
当您的工作是 CPU bound (the CPU does the work, and the peripherals are mostly idle) but here, you are trying to improve the performance of a task which is I/O bound 时(CPU 大部分时间空闲,等待繁忙的外围设备),并行处理是有意义的。在这种情况下,增加并行性只会增加拥塞,因为多个任务将争夺它们之间已经很紧迫的 I/O 带宽。
在 macOS 上,系统已经为您的所有数据编制了索引(包括文字处理文档、PDF、电子邮件等的内容);在右上角的菜单栏上有一个友好的放大镜,您可以在其中访问更快、更通用的搜索,称为 Spotlight。 (虽然我同意 find
缺少一些更复杂的控件;而且“用户友好”的设计在它猜我想要的东西时妨碍了我,但猜错了。)
一些 Linux 发行版提供了类似的功能;我希望这会成为如今带有 GUI 的任何东西的标准,尽管细节会因系统而异。
任何类 Unix 系统上更传统的解决方案是 locate
命令,它执行类似但更有限的任务;它将在文件名上创建一个(非常活泼的)索引,所以你可以说
locate fnord
非常快速地获取名称匹配 fnord
的每个文件。该索引只是昨晚 find
运行 结果的副本(或者您将后端安排为 运行)。该命令已安装在 macOS 上,但如果要使用它,则必须启用后端。 (只需 运行 locate locate
即可获得进一步说明。)
例如,如果您发现自己经常寻找具有特定权限集和特定所有者的文件(这些不是 locate
记录的功能),您可以自己构建类似的东西;只是 运行 每晚(或每小时等)find
将这些特征收集到数据库中——甚至只是一个文本文件——然后你几乎可以立即搜索它。
对于 运行 并行作业,您实际上并不需要 GNU parallel
,尽管它确实为许多用例提供了许多便利和增强功能;您已经 xargs -P
。 (源自 BSD 的 macOS 上的 xargs
比 GNU xargs
更受限制,这是你会在许多 Linuxes 上找到的东西;但它确实有 -P
选项.)
例如,这里是 运行 八个并行 find
实例 xargs -P
:
printf '%s\n' */ | xargs -I {} -P 8 find {} -name '*.ogg'
(假设通配符不匹配包含单引号或换行符或其他恶作剧的目录;GNU xargs
有 -0
选项来修复大量类似的极端情况;那么您将使用 '%s[=32=]'
作为 printf
的格式字符串。)
正如 the parallel
documentation 所解释的那样,它的一般语法是
parallel -options command ...
其中 {}
将替换为当前输入行(如果缺少,将在 command ...
末尾隐式添加)和(显然可选):::
特殊标记允许您在命令行上指定输入源而不是标准输入。
这些特殊标记之外的任何内容都会逐字传递,因此您可以添加 find
选项,只需按字面说明即可。
parallel -j8 find {} -type f -name '*.ogg' ::: */
我不会说话 zsh
但重构为常规 POSIX sh
你的函数可能类似于
ff () {
parallel -j8 find {} -type f -iname "" ::: ""
}
尽管我可能会切换参数以便您可以指定名称模式和要搜索的文件列表,à la grep
.
ff () {
# "local" is not POSIX but works in many sh versions
local pat=
shift
parallel -j8 find {} -type f -iname "$pat" ::: "$@"
}
但再次强调,旋转磁盘以查找已编入索引的内容可能是您应该停止做的事情,而不是促进。
正如其他人所写的那样,find
I/O 很重,很可能不受您的 CPU 限制。
但是根据您的磁盘,可以更好地 运行 并行作业。
NVMe 磁盘以在并行访问 运行 4-8 次时性能最佳而著称。一些网络文件系统还可以更快地处理多个进程。
所以一定程度的并行化是有意义的,但您确实必须进行测量才能确定。
并行化 find
8 个作业 运行ning 并行:
parallel -j8 find {} ::: *
如果你在一个有很多子目录的目录中,这种方法效果最好:然后将并行搜索每个子目录。否则这可能会更好:
parallel -j8 find {} ::: */*
基本相同的想法,但现在使用目录的子目录。
如果您希望在找到结果后立即打印结果(而不是在 find
完成后),请使用 --line-buffer
(或 --lb
):
parallel --lb -j8 find {} ::: */*
要了解 GNU Parallel,请花 20 分钟阅读 https://doi.org/10.5281/zenodo.1146014 and print the cheat sheet: https://www.gnu.org/software/parallel/parallel_cheat.pdf
的第 1+2 章你的命令行会感谢你的。
您似乎希望能够在 macOS 下的大目录中快速定位文件。我认为该工作的正确工具是 mdfind
.
我在我的主目录下创建了一个包含 10,000,000 个文件的层次结构,所有文件都具有类似于 UUID 的唯一名称,例如80104d18-74c9-4803-af51-9162856bf90d
。然后我试图找到一个:
mdfind -onlyin ~ -name 80104d18-74c9-4803-af51-9162856bf90d
结果是即时的,而且速度太快,无法测量时间,所以我进行了 100 次查找,用时不到 20 秒,所以平均一次查找需要 0.2 秒。
如果您真的想查找 100 个文件,您可以像这样将它们分组到一个搜索中:
mdfind -onlyin ~ 'kMDItemDisplayName==ffff4bbd-897d-4768-99c9-d8434d873bd8 || kMDItemDisplayName==800e8b37-1f22-4c7b-ba5c-f1d1040ac736 || kMDItemDisplayName==800e8b37-1f22-4c7b-ba5c-f1d1040ac736'
而且执行速度更快。
如果您只知道部分文件名,您可以使用:
mdfind -onlyin ~ "kMDItemDisplayName = '*cdd90b5ef351*'"
/Users/mark/Whosebug/MassiveDirectory/800f0058-4021-4f2d-8f5c-cdd90b5ef351
您还可以在搜索中使用创建日期、文件类型、作者、视频持续时间或标签。例如,您可以像这样查找名称包含“25DD954D73AF”的所有 PNG 图片:
mdfind -onlyin ~ "kMDItemKind = 'PNG image' && kMDItemDisplayName = '*25DD954D73AF*'"
/Users/mark/Whosebug/MassiveDirectory/9A91A1C4-C8BF-467E-954E-25DD954D73AF.png
如果您想知道可以搜索哪些字段,请获取您希望能够查找的类型的文件,然后 运行 mdls
在上面,您将看到所有macOS 知道的字段:
mdls SomeMusic.m4a
mdls SomeVideo.avi
mdls SomeMS-WordDocument.doc
更多示例here。
此外,与 locate
不同的是,不需要经常更新数据库。