繁体   English   中英

连接线程中的性能问题

[英]Performance issues in joining threads

我编写了以下并行代码,用于检查vector向量中的所有元素。 我只存储满足给定条件的vector<vector<int> >那些元素。 但是,我的问题是vector<vector<int> >某些向量非常大,而另一些则很小。 由于这个原因,我的代码需要很长时间才能执行thread.join()。 有人可以建议我如何提高代码性能。

void check_if_condition(vector<int>& a, vector<int>& satisfyingElements)
{
    for(vector<int>::iterator i1=a.begin(), l1=a.end(); i1!=l1; ++i1)
        if(some_check_condition(*i1))
            satisfyingElements.push_back(*i1);

}

void doWork(std::vector<vector<int> >& myVec, std::vector<vector<int> >& results, size_t current, size_t end)
{
    end = std::min(end, myVec.size());
    int numPassed = 0;
    for(; current < end; ++current) {
        vector<int> satisfyingElements;
        check_if_condition(myVec[current], satisfyingElements); 
        if(!satisfyingElements.empty()){
            results[current] = satisfyingElements;            
        }
    }    
}

int main()
{
    std::vector<std::vector<int> > myVec(1000000);
    std::vector<std::vector<int> > results(myVec.size());   
    unsigned numparallelThreads = std::thread::hardware_concurrency();

    std::vector<std::thread> parallelThreads;
    auto blockSize = myVec.size() / numparallelThreads;
    for(size_t i = 0; i < numparallelThreads - 1; ++i) {
        parallelThreads.emplace_back(doWork, std::ref(myVec), std::ref(results), i * blockSize, (i+1) * blockSize);
    }

    //also do work in this thread
    doWork(myVec, results, (numparallelThreads-1) * blockSize, myVec.size());

    for(auto& thread : parallelThreads)
        thread.join();

    std::vector<int> storage;
    storage.reserve(numPassed.load());

    auto itRes = results.begin();
    auto itmyVec = myVec.begin();
    auto endRes = results.end();
    for(; itRes != endRes; ++itRes, ++itmyVec) {
        if(!(*itRes).empty())
            storage.insert(storage.begin(),(*itRes).begin(), (*itRes).end());
    }

    std::cout << "Done" << std::endl;
}

很高兴看到您是否可以为那些“较大的”内部向量提供一定比例,以查看问题的严重程度。

但是,我认为您的问题是这样的:

for(auto& thread : parallelThreads)
    thread.join();

该位依次使所有线程依次通过并等待它们完成,然后才查看下一个线程。 对于线程池,您要等待每个线程完成。 这可以通过对每个线程使用condition_variable完成。 在他们完成之前,他们必须通知condition_variable您可以等待。

查看您的实现,这里更大的问题是工作线程的消耗不平衡。

为了使所有线程上的负载更加均衡,您需要展平数据结构,以便不同的工作线程可以处理大小相对相似的数据块。 我不确定您的数据来自哪里,但是在处理大型数据集的应用程序中使用向量的向量听起来并不是一个好主意。 将现有的向量向量处理为一个向量,或者尽可能读取数据。 如果您需要处理行号,则可以保留一个起始范围的向量,从中可以找到行号。

一旦有了一个大向量,就可以将其分解成相等大小的块,以馈入工作线程。 其次,您不想在堆栈上构建向量并将它们推入另一个向量,因为很可能在线程工作期间遇到分配内存的问题。 分配内存是一个全局状态更改,因此将需要一定程度的锁定(但可以避免使用适当的地址分区)。 根据经验,每当您寻求性能时,都应从性能关键部件中删除动态分配。

在这种情况下,您的线程可能宁愿“标记”满足条件的元素,而不是构建满足条件的元素的向量。 一旦完成,您就可以只遍历好对象而无需推送和复制任何内容。 这样的解决方案将减少浪费。

实际上,如果我是您,我会尝试在单个线程上首先解决上述问题,并执行上面的建议。 如果您摆脱了vector-of-vectors结构,并有条件地遍历元素(这可能像使用C ++ 11标准库提供的xxxx_if算法一样简单),则最终可能会获得足够不错的性能。 而且只有在这一点上,才值得看一下将这项工作的大部分任务委派给工作线程。 在您的代码中,此时几乎没有理由使用辅助线程来过滤它们。 尽可能少地写作和移动,您将获得很多性能。 并行化仅在某些情况下有效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM