大图像集上图像处理程序的并行化

时间:2015-02-05 01:30:50

标签: bash image-processing parallel-processing scientific-computing

我目前有一个非常大的目录,其中包含超过9000个文件夹,每个文件夹中包含jpeg图像(平均每个文件夹40个)。

我的程序获取图像的输入文件夹,并将该文件夹中图像的特征向量输出到文本文件:

./process_image images/ output/

我还有一个脚本,其用法如下:

./script.sh dirlist.txt images/ output/ 1

第一个输入dirlist.txt包含输入目录中的文件夹名称 第2和第3个输入是输入和输出的基本目录。 第四个参数是我想要访问的dirlist中的条目的索引

上面的例子会调用,假设imageset1在dirlist.txt中的索引1处:

./process_image images/imageset1/ output/imageset1/

如果我按顺序执行此操作,则需要几天的时间来处理所有9000个文件夹。在这种情况下,最好的并行化方法是什么?我应该编写一个脚本,将9000个文件夹分成块并分别运行脚本,每个脚本运行一定范围的索引吗?另外,如果一个可执行文件在RAM中的范围从100 MB到1GB,我该如何确定我可以运行多少个程序?我有32 GB的RAM。

2 个答案:

答案 0 :(得分:5)

我每天定期处理65,000多张图片,而且我总是使用GNU Parallel - 请参阅herehere。我不打算并行化C代码!

它允许您指定并行运行的作业数,或者仅使用每个CPU核心一个作业的默认值。它使用起来非常简单。你所要做的就是改变你的script.sh,这样它就可以将所有它已经开始的命令(每行一个)转发到stdout,而不是开始工作。你把它输入parallel,就像这样

script.sh | parallel

您可以添加-j 8之类的标记来并行运行8个作业,或-k以保持输出顺序(如果相关)。

script.sh | parallel -j 8 -k

同样,如果您担心内存使用情况,您可以告诉parallel仅在系统具有至少1GB可用内存时才启动新作业:

script.sh | parallel --memfree 1G

您还可以添加其他计算机的列表,并为您分配作业: - )

这是一个很小的例子:

#!/bin/bash
# script.sh

for i in {0..99}; do
   echo "echo Start job $i; sleep 5; echo End job $i"
done

然后

script.sh | parallel

并且我的8核机器上的500秒工作在70秒内完成,如果我使用parallel -j 25则需要21秒。

答案 1 :(得分:0)

  1. 瓶颈

    • CPU使用率不是有效的瓶颈标志
    • 决定瓶颈的最佳方法是通过测量
    • 当你遇到瓶颈时,CPU使用率通常达到100%或接近
    • 但这只意味着达到了一些瓶颈
    • 如果瓶颈来自IO,那么CPU使用率可能会很低......
    • 测量CPU / MEM,您需要使用不同的CPU和传输速度
    • 因此更改BIOS中的设置以查看时间是否快速变化
    • 在这种情况下,这并不总是有助于确定来源
    • 你必须测量你的程序部分的运行时间,看看什么是慢的
    • 然后根据代码的这一部分
    • 自行确定
    • 还有一些分析工具可以自动完成其中一些工作
  2. 并行化

    • 您只能并行化代码的线程安全部分
    • 所以如果你使用非线程安全的库,那么这些部分不能并行化
    • 如果你有相互依赖的代码部分,那么并行化就不会太多了
    • 在不了解任务的处理背景的情况下很难说
    • 最简单,最安全的方法是每个线程的进程文件夹
  3. 线程数

    • 我通常使用尽可能多的线程,因为我有可用的CPU
    • 此数字可从系统关联性
    • 获得(在Windows上)
    • 关于时间要求严格的应用程序我使用第一个CPU作为主要代码,其余只作为线程
    • 在您的情况下使用太多线程将导致IO与其他线程发生冲突(除非您有RAM / SSD驱动器)
  4. 调度

    • 对于类似的任务持续时间,只需将任务划分为线程
    • 对于非常不同的任务,运行时使用某种调度
    • 例如create que of tasks
    • 然后定期检查所有线程是否正忙
    • 找到第一个免费线程并从que获取任务
    • 不要忘记将Sleep()添加到此循环
    • 如果完成所有任务,则停止所有线程并退出