opencv 多进程的小加速
Posted
技术标签:
【中文标题】opencv 多进程的小加速【英文标题】:Small speedup with multiple processes for opencv 【发布时间】:2017-06-27 11:08:37 【问题描述】:在应用程序中,我必须分析电影文件 (假设计算连续帧对的差异)。 为此,我使用 opencv(它使用 ffmpeg 作为 lib/编解码器)。 根据视频格式,有不同的 CPU 负载/使用。 对于 wmv3,使用的核心似乎不超过 1 个。 因此,让多个线程处理电影的不同部分是非常接近的, 因为数据是独立的(除了必须在之后缝合部分)。 代码(由 lap 参数剥离)非常简单:
int main(int argc, char *argv[])
const string source = "move.wmv";
VideoCapture capt(source);
if (!capt.isOpened())
cout << "Could not open file " << source << endl;
return -1;
unsigned short nThreads (8);
double *pDiffArray = new double [(size_t) (capt.get(CV_CAP_PROP_FRAME_COUNT)];
capt.release();
ComputeDifferences (source, pDiffArray, nThreads);
return 0;
int ComputeDifferences (const string& source, double *pDiffArray, const unsigned short& nThreads)
std::vector<std::thread *> threadVector;
for (unsigned int i=0; i< nThreads; i++)
threadVector.push_back (new std::thread (ComputePart, source, pDiffArray, nThreads, i));
for (unsigned int i=0; i< nThreads; i++)
threadVector.at (i)->join();
// Stitching
;
return 0;
;
void ComputePart (const string source, double *pDiffArray,
const unsigned int& nThreads, const unsigned int& nThreadNo)
VideoCapture capt(source);
if (!capt.isOpened())
cout << "Could not open file " << source << endl;
size_t startPosDiffArray;
startPosDiffArray = nThreadNo * (capt.get(CV_CAP_PROP_FRAME_COUNT) / nThreads);
size_t sizePart (capt.get(CV_CAP_PROP_FRAME_COUNT) / nThreads);
size_t startPosFrame;
startPosFrame = capt.get(CV_CAP_PROP_FRAME_COUNT) / nThreads * nThreadNo;
capt.set(CAP_PROP_POS_FRAMES, startPosFrame);
Size refS = Size((int) capt.get(CAP_PROP_FRAME_WIDTH),
(int) capt.get(CAP_PROP_FRAME_HEIGHT));
Mat frame, frameRes;
std::array<Mat, 2> frameDuo;
Scalar s;
capt >> frameDuo [0];
if (!frameDuo [0].data)
return;
for (size_t i = 1; i < sizePart; i++)
capt >> frameDuo [i%2];
if (!frameDuo [i%2].data)
break;
absdiff (frameDuo [(i-1)%2], frameDuo [i%2], frameRes);
s = sum (frameRes);
pDiffArray [i-1+startPosDiffArray] = (s [0] + s [1] + s [2])/ (refS.height * refS.width);
capt.release();
如果我在 wmv3 视频上使用它,1280x720,abt。 50,000 帧, 相对于单线程(190 秒),我得到了这个加速(在 Intel i7 上)。
MT2 1.8 MT4 2.6 MT8 3.0除了非常失望之外,我不明白这里发生了什么。 我确实知道阿姆达尔定律等,但在这种情况下,我预计会有更好的加速。 有没有人对我有提示(作为新手)? 这不是定位(capt.set()),因为禁用不会改变任何东西。 是ffmpeg-lib、opencv、std-lib的线程切换、工作集问题吗?
[编辑:
根据 cmets 中的提示,我发现 80% 的时间用于
capt >> frameDuo [i%2];
这包括从文件中读取、解码和复制到 opencv 结构中。 从这里只有从文件中读取的内容是“顺序类型”的(在 Amdahl 的意义上)。 由于 HDD 没有显示大量访问(即使在 MT8 时),并且没有区别 使用快速 SSD 时,我不明白为什么这个顺序部分会产生如此大的影响。 怎么可能 8 个核心完全工作但只有 3 个加速? 还有:我怎样才能做得更好?]
【问题讨论】:
如果你知道阿姆达尔定律,结果应该不会那么令人惊讶,考虑到你有很多非平行的东西。 可能我理解的不正确。在我看来,没有任何非平行的东西(???)。你能具体点吗?也许然后:如何变得更好...... 总有一个不平行的部分。你打开一个文件,你开始和加入线程等等...... 是的,当然,我明白。但是这些操作(打开文件、启动和加入线程)确实只完成了相当长的(190 秒)工作的一小部分。其中大部分(线程内的处理)应该完全独立完成(???) 你怎么知道它只是很小的一部分?你量过吗?VideoCapture capt(source);
在做什么?
【参考方案1】:
您的大部分数字确实可以用阿姆达尔定律来解释。 如果我将你的结果用于两个线程并尝试计算并行完成的分数,我会得到 p = 0.88888 的值。并将这个值用于 4/8 线程我得到
2 1.8
4 2.99
8 4.48
这些数字并不能精确地再现您测量的结果,但根据 Amdahls 定律,每个线程都有开销,并且必须考虑更多的东西才能获得真实的数字,所以它只是一个初步近似值,从这个意义上说协议还可以。
作为结论:你得到的数字并没有那么糟糕。当考虑阿姆达尔定律时,这正是人们所期望的大约 85% 的平行分数。
【讨论】:
如何计算并行完成的分数? @KjMag 来自***:S = 1 / (1-p + p/s) 其中 S=1.8 和 s=2 我得到 p = 0.888888以上是关于opencv 多进程的小加速的主要内容,如果未能解决你的问题,请参考以下文章
python 复习—并发编程实战——线程多进程多协程加速程序运行实例(多线程和多进程的对比)