并行执行四个任务...我该怎么做?

并行执行四个任务...我该怎么做?

我的目录中有一堆 PNG 图像。我有一个名为 pngout 的应用程序,我运行它来压缩这些图像。该应用程序由我编写的脚本调用。问题是这个脚本一次执行一个操作,如下所示:

FILES=(./*.png)
for f in  "${FILES[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 $f R${f/\.\//}
done

一次仅处理一个文件需要花费大量时间。运行这个应用程序后,我发现 CPU 只有 10%。所以我发现我可以将这些文件分成 4 个批次,将每个批次放入一个目录中,然后从四个终端窗口、四个进程中触发 4 个,因此我有四个脚本实例,同时处理这些图像和工作占用了1/4的时间。

第二个问题是我浪费了时间分割图像和批次并将脚本复制到四个目录,打开4个终端窗口,等等......

如何用一个脚本来实现这一点,而无需分割任何东西?

我的意思是两件事:首先,如何从 bash 脚本将进程启动到后台? (只需在末尾添加&?)第二:发送第四个任务后如何停止向后台发送任务并让脚本等待任务结束?我的意思是,只是在一个任务结束时向后台发送一个新任务,始终保持 4 个任务并行?如果我不这样做,循环将向后台发送无数的任务,并且 CPU 将堵塞。

答案1

xargs如果您有支持并行执行的副本-P,您可以简单地执行

printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}

对于其他想法,Wooledge Bash wiki 有一个部分在流程管理文章中准确描述了您想要的内容。

答案2

除了已经提出的解决方案之外,您还可以创建一个 makefile,描述如何从未压缩文件生成压缩文件,并用于make -j 4并行运行 4 个作业。问题是您需要以不同的方式命名压缩文件和未压缩文件,或者将它们存储在不同的目录中,否则编写合理的 make 规则将是不可能的。

答案3

如果您有 GNU Parallelhttp://www.gnu.org/software/parallel/安装后你可以这样做:

parallel ./pngout -s0 {} R{} ::: *.png

您可以简单地通过以下方式安装 GNU Parallel:

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem

观看 GNU Parallel 的介绍视频以了解更多信息: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

答案4

回答你的两个问题:

  • 是的,在行尾添加 & 将指示您 shell 启动后台进程。
  • 使用该wait命令,您可以要求 shell 等待后台的所有进程完成,然后再继续。

这是修改后的脚本,j用于跟踪后台进程的数量。当NB_CONCURRENT_PROCESSES达到该值时,脚本将重置j为 0 并等待所有后台进程完成,然后再恢复执行。

files=(./*.png)
nb_concurrent_processes=4
j=0
for f in "${files[@]}"
do
        echo "Processing $f file..."
        # take action on each file. $f store current file name
        ./pngout -s0 "$f" R"${f/\.\//}" &
        ((++j == nb_concurrent_processes)) && { j=0; wait; }
done

相关内容