根据下面显示的地图给出数据结构:
std::map<int, std::set<std::vector<int>>> cliques;
键表示其中包含的向量的大小。
一开始,地图只有一个(例如[3]
),其中包含输入向量(例如{ {1}}和{1, 3, 5}
)。
我的功能将地图的最大键中存储的矢量和分解存储到所有可能的组合包含较少的元素,并将其存储在与新向量大小相对应的键中(例如{2, 4, 6}
)。
我不知道我的解决方案是否效率最高,但效果非常好。但由于我的项目旨在处理大量数据,我需要并行化我的代码,这使我进行了以下实现:
[2] = {1,3} {1,5} {3,5} {2,4} {2,6} {4,6} and [1] = {1} {3} {5} {2} {4} {6}
使用“omp parallel”和“omp single”(而不是“omp for”)可以安全地访问数据结构,同时允许所有其他操作并行运行。代码工作几乎完美,差不多......因为它在最终结果中遗漏了一些(很少的)子向量(如果禁用omp则成功生成)。
有没有“OMP专家”能够帮我解决这个问题?提前谢谢。
---------------
更新
答案 0 :(得分:2)
我不确定我理解算法的所有微妙之处,因此我不能完全确定我的分析。免责声明说,这就是我认为发生的事情:
omp single nowait
完成)允许线程在前一次迭代中工作,因为it
的值没有同步在这个阶段进行。 (注意:退出时保护迭代器增量的omp single
没有nowait
有一个隐式barrier
,它确保了该值的线程连贯视图,因此差异只能在当前迭代和前一个迭代)cliques[kNew].insert(new_clique);
实际上是所有可以爆炸的地方,因为对同一位置的访问是并发的,标准容器不支持。 (无论如何,这是错误的,达到我理解的极限)再说一次,请记住我最初的免责声明,但我认为你的算法本质上是非常错误的,原因有很多,并且它只是偶然地提供了一些接近你期望的东西。
最后,我打算向你提出一个我的算法,但由于你的代码片段中缺少很多部分,我只能这样做。 如果您发布了正确的mcve,那么也许我会。
<强>更新强> 根据您的代码,这是一个可能的并行版本:
for (int k = kMax; k > kMin; k--)
{
std::set<std::vector<int>>::iterator it = cliques[k].begin();
for(int s = 0; s < cliques[k].size(); ++s)
{
std::vector<int> clique = *it;
#pragma omp parallel for num_threads(max_threads)
for (int v = 0; v < clique.size(); ++v)
{
int& vertex = clique[v];
std::vector<int> new_clique;
std::copy_if(clique.begin(), clique.end(), std::back_inserter(new_clique), [vertex](const int& elem) { return elem != vertex; });
int kNew = k - 1;
#pragma omp critical
cliques[kNew].insert(new_clique);
}
it++;
}
}