C++ Boost:大图&;多线程
我需要从一个大数据集中创建一个非常大的有向图。我确信这些事情:C++ Boost:大图&;多线程,c++,multithreading,boost,graph,boost-graph,C++,Multithreading,Boost,Graph,Boost Graph,我需要从一个大数据集中创建一个非常大的有向图。我确信这些事情: 每个节点最多有K条传出边 我有一个N>>K个节点的列表(unordered\u map) 该图是通过比较所有节点来构建的(是的,很遗憾是O(N^2)) 考虑到这一点,我将使用std::thread并行创建图形,我想知道这是否可以通过Boost图形库实现 如果我使用邻接矩阵,应该可以预先分配矩阵(K*N个元素),因此插入所有相邻节点是线程安全的 我读过BGL可能是线程不安全的,但我发现的帖子已经有三年了 你知道有没有可能像我想的那
- 每个节点最多有K条传出边
- 我有一个N>>K个节点的列表(
)unordered\u map
- 该图是通过比较所有节点来构建的(是的,很遗憾是O(N^2))
std::thread
并行创建图形,我想知道这是否可以通过Boost图形库实现
如果我使用邻接矩阵,应该可以预先分配矩阵(K*N个元素),因此插入所有相邻节点是线程安全的
我读过BGL可能是线程不安全的,但我发现的帖子已经有三年了
你知道有没有可能像我想的那样?你建议换个方式吗
干杯 我认为你应该把你的目标分解成两个独立的子目标
一个稍微高效的设计是可以想象的,但需要大量关于线程安全的神秘知识。我提出的设计可以在没有晦涩知识或复杂代码的情况下实现,因此实现起来更快、更稳健,更易于维护。我认为您应该将目标分解为两个单独的子目标
一个稍微高效的设计是可以想象的,但需要大量关于线程安全的神秘知识。我提出的设计可以在没有晦涩知识或复杂代码的情况下实现,因此实现起来更快、更稳健,也更易于维护。几乎BGL中的任何图形算法都需要一个映射:顶点->整数,它为每个顶点指定一个[0,num_顶点(g)范围内的唯一整数)。此映射称为“顶点索引”,通常可作为属性映射访问 话虽如此,我可以假设您的顶点已经是整数或与某些整数关联(例如,无序的_映射在“mapped_type”中有一些额外字段)。如果您的输入顶点存储在连续的紧数组中(例如std::vector),则索引是自然的(为了性能和内存) 如果顶点与整数[关联],则内存紧张图的最佳选择是“”。该图是不可变的,因此需要在生成图之前填充边容器 正如RavenPoint所解释的,您的最佳选择是为每个线程配备其自己的本地结果容器,并仅在将本地结果合并到最终结果时锁定中心容器。这种策略通过TBB模板实现无锁。因此,图形构建的完整代码大致如下所示:
#include "tbb/blocked_range2d.h"
#include "tbb/parallel_reduce.h"
#include "boost/graph/compressed_sparse_row_graph.hpp"
typedef something vertex; //e.g.something is integer giving index of a real data
class EdgeBuilder
{
public:
typedef std::pair<int,int> edge;
typedef std::vector<edge> Edges;
typedef ActualStorage Input;
EdgeBuilder(const Input & input):_input(input){} //OPTIONAL: reserve some space in _edges
EdgeBuilder( EdgeBuilder& parent, tbb::split ): _input(parent.input){} // reserve something
void operator()( const const tbb::blocked_range2d<size_t>& r )
{
for( size_t i=r.rows().begin(); i!=r.rows().end(); ++i ){
for( size_t j=r.cols().begin(); j!=r.cols().end(); ++j ) {
//I assume you provide some function to compute existence
if (my_func_edge_exist(_input,i, j))
m_edges.push_back(edge(i,j));
}
}
}
//merges local results from two TBB threads
void join( EdgeBuilder& rhs )
{
m_edges.insert( m_edges.end(), rhs.m_edges.begin(), rhs.m_edges.end() );
}
Edges _edges; //for a given interval of vertices
const Input & _input;
};
//full flow:
boost::compressed_sparse_row_graph<>* build_graph( const Storage & vertices)
{
EdgeBuilder builder(vertices);
tbb::blocked_range2d<size_t,size_t> range(0,vertices.size(), 100, //row grain size
0,vertices.size(), 100); //col grain size
tbb::parallel_reduce(range, builder);
boost::compressed_sparse_row_graph<>
theGraph = new boost::compressed_sparse_row_graph<>
(boost::edges_are_unsorted_multi_pass_t,
builder._edges.begin(), builder._edges.end(),
vertices.size() );
return theGraph;
}
#包括“tbb/blocked_range2d.h”
#包括“tbb/parallel_reduce.h”
#包括“boost/graph/compressed\u sparse\u row\u graph.hpp”
typedef something vertex;//例如,something是一个整数,给出实际数据的索引
类EdgeBuilder
{
公众:
typedef std::对边;
typedef std::向量边;
类型定义实际存储输入;
EdgeBuilder(常量输入和输入):\u输入(输入){}//可选:在\u边中保留一些空间
EdgeBuilder(EdgeBuilder&parent,tbb::split):\u输入(parent.input){}//保留某些内容
void运算符()
{
对于(大小i=r.rows().begin();i!=r.rows().end();++i){
对于(大小j=r.cols().begin();j!=r.cols().end();++j){
//我假设你提供了一些函数来计算存在性
如果(我的函数边存在(_输入,i,j))
m_边。向后推(边(i,j));
}
}
}
//合并来自两个TBB线程的本地结果
无效连接(EdgeBuilder和rhs)
{
m_edges.insert(m_edges.end()、rhs.m_edges.begin()、rhs.m_edges.end());
}
边_边;//对于给定的顶点间隔
常量输入&_输入;
};
//全流量:
boost::压缩的稀疏行图*构建图(常量存储和顶点)
{
EdgeBuilder生成器(顶点);
tbb::阻塞范围2D范围(