我找到了接近这个的答案,但不明白如何在我的情况下使用它们(我对 Bash 很陌生)......所以,我正在尝试处理一个包含大图像序列的文件夹(100k + 文件)使用 Imagemagick 并希望使用 GNU Parallel 来加快速度。
这是我使用的代码(一次处理 100 帧以避免内存不足):
calcmethod1=mean;
allframes=(*.png)
cd out1
for (( i=0; i < "${#allframes[@]}" ; i+=100 )); do
convert "${allframes[@]:i:100}" -evaluate-sequence "$calcmethod1" \
-channel RGB -normalize ../out2/"${allframes[i]}"
done
我将如何“并行化”这个?我发现大多数解决方案不使用循环而是使用管道 - 但是这样做我遇到了我的脚本会因为我的参数列表太长而中断的问题......
我想我想要做的是parallel
拆分负载,例如将前 100 帧交给核心 1,将 100-199 帧交给核心 2 等等?
正确的解决方案是使用内置的 shell 打印文件名,这样
printf '%s\0' *.png
不会受到命令行参数长度的 ARG_MAX 限制的影响,然后通过管道将parallel --null
其读取这些文件名并根据需要批处理作业。parallel
我们将使用的一些功能:--null
需要在空字符上合理拆分文件名,以防止奇怪的文件名出现奇怪的问题-n 100
就像 xargs 一样,每次调用都会处理 100 个文件{}
包含这 100 个文件名../out2/{1}
仅包含第一个所以,这将变成:
为什么你认为管道不起作用?管道工作正常,只有不从管道读取的外部分叉命令存在参数长度问题。管道实际上是
parallel
.命令
您的示例程序似乎并不关心您正在构建
*.png
的allframes
数组的顺序,但您的评论让我相信顺序很重要。重击
因此,我将从像这样修改您的脚本开始,更改
allframes
数组的结构,以便文件按数字顺序存储。这可以进一步简化为
sort -zV
:这对构建您的
convert ...
命令有影响,因此它们现在看起来像这样:平行线
基于 eschwartz 的示例,我整理了一个
parallel
示例,如下所示:再次,更简单地使用
sort -zV
:注意:上面有一个 echo "..." 作为
parallel
开始的动作。这样做有助于可视化正在发生的事情:如果您对此输出感到满意,只需将
--dryrun
开关移至parallel
,然后重新运行即可。参考
convert
可以在自己的子 shell 中运行每个进程:要查看它是如何工作的,请尝试以下脚本:
分配给脚本名称
par.sh
并随后检查进程:我们可以假设本机 Linux CPU 负载平衡器应该在 CPU 内核之间均匀分布进程,因为每个子 shell 都有一个单独的 pid。
cpuset
无论如何,总是可以使用类似的东西。