如何有效地合并TBB线程的结果

时间:2016-10-17 09:28:15

标签: c++ multithreading opencv tbb

我正在研究对象的视觉检测,我使用Opencv的级联分类器。它效果很好,但对我来说太慢了。我使用Vtune来获取所有热点,我发现在执行140次(CPU时间,实际大约是60s)时,有123s的开销时间。 cvCascadeClassifier使用TBB更快,但似乎所有TBB线程等待的次数超过应有的水平。 有代码:

void operator()(const Range& range) const
{
    Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone();

    Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor));

    int y1 = range.start * stripSize;
    int y2 = min(range.end * stripSize, processingRectSize.height);
    for( int y = y1; y < y2; y += yStep )
    {
        for( int x = 0; x < processingRectSize.width; x += yStep )
        {
            if ( (!mask.empty()) && (mask.at<uchar>(Point(x,y))==0)) {
                continue;
            }

            double gypWeight;
            int result = classifier->runAt(evaluator, Point(x, y), gypWeight);

            #if defined (LOG_CASCADE_STATISTIC)
            logger.setPoint(Point(x, y), result);
            #endif
            if( rejectLevels )
            {
                if( result == 1 )
                    result =  -(int)classifier->data.stages.size();
                if( classifier->data.stages.size() + result < 4 )
                {
                    mtx->lock();
                    rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height));
                    rejectLevels->push_back(-result);
                    levelWeights->push_back(gypWeight);
                    mtx->unlock();
                }
            }
            else if( result > 0 )
            {
                mtx->lock();
                rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor),
                                           winSize.width, winSize.height));
                mtx->unlock();
            }
            if( result == 0 )
                x += yStep;
        }
    }
}

我认为问题来自合并结果。互斥锁定太多,线程需要经常等待。这部分代码被称为很多时间,并且只有很少的线程(在我的情况下为3)。我试图为每个线程创建局部向量(我没有尝试使用list,因为Rect类型非常小)并在最后合并所有这些向量。这个解决方案减少了开销时间(140秒的CPU时间不到10秒),但我想要更多。

这是我的问题: 有没有办法有效地合并来自不同TBB线程的结果(也就是减少开销时间)?

编辑: 就我而言,我在链接过程中发现了一个错误。创建局部向量并在最后使用互斥锁合并效果很好。现在,我在140秒的CPU时间内有0.1秒的开销。这是一个特殊情况,很少有元素。安东的答案似乎更通用

2 个答案:

答案 0 :(得分:3)

结合结果还有另一种也许更有效的方法。使用combinable"ets"类来收集每个线程/任务的.local()结果(不要直接使用线程),然后使用.combine()结合结果

答案 1 :(得分:2)

您可以尝试使用TBB concurrent_vectorgrow_by接口可以帮助您减少插入开销:您可以在堆栈上创建小型(例如16个elem)数组,并在concurrent_vector中合并其中的所有元素。

此外,您可以使用带有concurrent_vector的C ++ 11替换#titles{ background-color: #f5f5f5; color: #069; fill: #069; } push_back