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

Duc*_*uck 25 shell background-process parallelism

我在一个目录中有一堆 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
Run Code Online (Sandbox Code Playgroud)

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

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

如何用一个脚本做到这一点,而不必分割任何东西?

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

jw0*_*013 34

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

printf '%s\0' *.png | xargs -0 -I {} -P 4 ./pngout -s0 {} R{}
Run Code Online (Sandbox Code Playgroud)

对于其他想法,Wooledge Bash wiki在 Process Management 文章中有一个部分准确描述了您想要什么。

  • @EugeneS 这是为了最大程度的正确性和稳健性。文件名不是行,[`ls` 不能用于可移植和安全地解析文件名](http://mywiki.wooledge.org/ParsingLs)。用于分隔文件名的唯一安全字符是 `\0` 和 `/`,因为所有其他字符,包括 `\n`,都可以是文件名本身的一部分。`printf` 使用 `\0` 来分隔文件名,`-0` 通知 `xargs`。`-I{}` 告诉 `xargs` 用参数替换 `{}`。 (4认同)
  • 还有为这种情况设计的“gnu parallel”和“xjobs”。这主要是您喜欢的口味问题。 (2认同)
  • 抱歉不准确。我特别感兴趣的是你为什么在这里使用 `printf` 函数而不是普通的 `ls .. | grep .. *.png`?我也对你使用的 `xargs` 参数(`-0` 和 `-I{}`)感兴趣。谢谢! (2认同)

900*_*000 9

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


Ole*_*nge 8

如果你安装了 GNU Parallel http://www.gnu.org/software/parallel/你可以这样做:

parallel ./pngout -s0 {} R{} ::: *.png
Run Code Online (Sandbox Code Playgroud)

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

wget http://git.savannah.gnu.org/cgit/parallel.git/plain/src/parallel
chmod 755 parallel
cp parallel sem
Run Code Online (Sandbox Code Playgroud)

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


Fre*_*rdt 7

回答你的两个问题:

  • 是的,在行尾添加 & 将指示您的 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
Run Code Online (Sandbox Code Playgroud)