我找到了与此接近的答案,但无法理解如何在我的情况下使用它们(我对 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 等等?
答案1
命令
您的示例程序似乎并不关心您正在构造的数组的顺序*.png
,allframes
但您的评论让我相信顺序很重要。
我想我想做的是并行分割负载,例如将前 100 帧交给核心 1,将帧 100-199 交给核心 2 等?
重击
因此,我首先对脚本进行修改,如下所示,更改allframes
数组的结构,以便文件按数字顺序存储。
allframes=($(printf "%s\n" *.png | sort -V | tr '\n' ' '))
这可以使用以下方法进一步简化sort -zV
:
allframes=($(printf "%s\0" *.png | sort -zV | tr '\0' ' '))
这会对构建convert ...
命令产生影响,使它们现在看起来像这样:
$ convert "0.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png \
10.png 11.png 12.png 13.png 14.png 15.png 16.png 17.png 18.png \
19.png 20.png 21.png 22.png 23.png 24.png 25.png 26.png 27.png \
28.png 29.png 30.png 31.png 32.png 33.png 34.png 35.png 36.png \
37.png 38.png 39.png 40.png 41.png 42.png 43.png 44.png 45.png \
46.png 47.png 48.png 49.png 50.png 51.png 52.png 53.png 54.png \
55.png 56.png 57.png 58.png 59.png 60.png 61.png 62.png 63.png \
64.png 65.png 66.png 67.png 68.png 69.png 70.png 71.png 72.png \
73.png 74.png 75.png 76.png 77.png 78.png 79.png 80.png 81.png \
82.png 83.png 84.png 85.png 86.png 87.png 88.png 89.png 90.png \
91.png 92.png 93.png 94.png 95.png 96.png 97.png 98.png 99.png" \
-evaluate-sequence "mean" -channel RGB -normalize ../out2/0.png
相似之处
在 eschwartz 的示例的基础上,我整理了一个parallel
示例,如下所示:
$ printf '%s\n' *.png | sort -V | parallel -n100 --dryrun convert {} \
-evaluate-sequence 'mean' -channel RGB -normalize ../out2/{1}
再次,更简单地使用sort -zV
:
$ printf '%s\0' *.png | sort -zV | parallel -0 -n100 --dryrun "convert {} \
-evaluate-sequence 'mean' -channel RGB -normalize ../out2/{1}
笔记:上面有一个回显“...”作为parallel
开始的操作。这样做有助于可视化正在发生的事情:
$ convert 0.png 1.png 2.png 3.png 4.png 5.png 6.png 7.png 8.png 9.png 10.png \
11.png 12.png 13.png 14.png 15.png 16.png 17.png 18.png 19.png \
20.png 21.png 22.png 23.png 24.png 25.png 26.png 27.png 28.png \
29.png 30.png 31.png 32.png 33.png 34.png 35.png 36.png 37.png \
38.png 39.png 40.png 41.png 42.png 43.png 44.png 45.png 46.png \
47.png 48.png 49.png 50.png 51.png 52.png 53.png 54.png 55.png \
56.png 57.png 58.png 59.png 60.png 61.png 62.png 63.png 64.png \
65.png 66.png 67.png 68.png 69.png 70.png 71.png 72.png 73.png \
74.png 75.png 76.png 77.png 78.png 79.png 80.png 81.png 82.png \
83.png 84.png 85.png 86.png 87.png 88.png 89.png 90.png 91.png \
92.png 93.png 94.png 95.png 96.png 97.png 98.png 99.png \
-evaluate-sequence mean -channel RGB -normalize ../out2/0.png
如果您对此输出感到满意,只需将开关移至--dryrun
,parallel
然后重新运行即可。
$ printf '%s\0' *.png | sort -zV | parallel -0 -n100 convert {} \
-evaluate-sequence 'mean' -channel RGB -normalize
参考
答案2
正确的解决方案是使用 shell 内置命令打印文件名,printf '%s\0' *.png
该命令不易受到命令行参数长度的 ARG_MAX 限制的影响,然后通过管道将其parallel --null
读取这些文件名并根据需要对作业进行批处理。
parallel
我们将使用其中的一些功能:
--null
需要在空字符上合理地分割文件名,以防止奇怪的文件名出现奇怪的问题-n 100
就像 xargs 一样,每次调用都会处理 100 个文件{}
包含这 100 个文件名../out2/{1}
仅包含第一个
所以,这将变成:
calcmethod1=mean
printf '%s\0' *.png | parallel --null -n 100 convert {} -evaluate-sequence $calcmethod1 -channel RGB -normalize {} ../out2/{1}
您认为为什么管道不起作用?管道工作正常,只有外部分支命令才可以不是从管道读取,有问题参数长度。管道实际上就是parallel
.
答案3
可以convert
在自己的子 shell 中运行每个进程:
#!/bin/bash
for (( i=1; i<=1000; i++ )) do
(
command --options ) &
disown
done
exit 0
要了解它是如何工作的,请尝试以下脚本:
#!/bin/bash
echo "Hi!"
for (( i=1; i<=1000; i++ )) do
(
sleep 30
echo "Bye, "$i"!" ) &
disown
done
exit 0
指定脚本名称par.sh
并随后检查进程:
ps aux | grep par.sh
我们可以假设本机 Linux CPU 负载平衡器应该在 CPU 核心之间均匀分布进程,因为每个子 shell 都有一个单独的 pid。无论如何,类似的东西cpuset
总是可以使用的。