Boost:大图和多线程
Boost: Big graphs & Multithreading
我需要从大数据集创建一个可以相当大的有向图。我肯定知道这些事情:
- 每个节点最多有 K 条传出边
- 我有一个 N 个>> K 个节点的列表 (
unordered_map
- 该图是通过将所有节点相互比较来构建的(是的,不幸的是,O(N^2)
考虑到这一点,我会使用 std::thread
并行创建图形,我想知道这是否可以通过 Boost 图形库来完成。
如果我使用邻接矩阵,应该可以预分配矩阵(K*N 元素),因此插入所有相邻节点是线程安全的。
我读过BGL可能是线程不安全的,但我找到的帖子已经有三年的历史了。
你知道是否有可能做到我的想法吗?你建议不这样做吗?
干杯!
BGL 中几乎任何图形算法都需要映射:vertex -> int,它为每个顶点分配一个 [0, num_vertices(g) ) 范围内的唯一整数。此映射称为"vertex_index",通常可作为property_map访问。
话虽如此,我可以假设您的顶点已经是整数或与某些整数相关联(例如,您的unordered_map在"mapped_type"中有一些额外的字段)。如果输入顶点存储在连续的紧密数组中,例如 std::vector,则更好(对于性能和内存),那么索引是很自然的。
如果顶点与整数[关联],则内存紧密图的最佳选择是"压缩稀疏行图"。图形是不可变的,因此您需要在生成图形之前填充边缘容器。
正如 ravenspoint 所解释的那样,最好的选择是为每个线程配备自己的本地结果容器,并且仅在将本地结果合并到最终结果时锁定中央容器。这种策略由TBB模板tbb::p arallel_reduce无锁实现。因此,用于图形构建的完整代码大致如下所示:
#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;
}
我认为你应该把你的目标分解成两个单独的子目标。
-
通过对节点对执行 N * ( N - 1) 测试来创建节点之间的链接。 您似乎知道如何将其分解为独立的线程。 将结果存储在您知道是线程安全的数据结构中,而不必担心 boost:graph 的奥秘。
-
从您的节点和(刚刚创建的)链接创建 boost::graph。
关于存储在每个线程中创建的链接的注意事项:找到合适的线程安全数据结构并不容易。 如果使用 STL 动态分配结构,那么您必须担心制作线程安全分配器,这是一个挑战。 如果你预先分配,那么有很多meessy代码来处理分配。 因此,我建议将每个线程创建的链接存储在单独的数据结构中,这样它们就不必是线程安全的。 创建所有链接后,可以逐个循环访问每个线程创建的链接。
可以想象一个稍微高效的设计,但需要大量关于线程安全的神秘知识。 我提出的设计可以在没有晦涩的知识或棘手的代码的情况下实现,因此将更快、更健壮地实现,并且更容易维护。
- boost::文件系统::recursive_directory_iterator多线程安全
- 如何正确取消析构函数中的 Boost deadline_timer(在多线程环境中)?
- 使用Boost将单线线程转换为多线程
- 重写多线程事件驱动的C 程序以使用单线程Boost :: Asio
- 来自 boost 的 udp 服务器不适用于多线程,但仅在主线程上工作
- 是boost :: lockfree :: Queue(在多线程程序中)可锁定
- Boost.Asio、tcp::iostream 和多线程
- CMAKE 不使用 Boost 多线程库
- 如何在多线程程序中使用 boost::asio 正确处理 fork()
- boost::shared_ptr代码中的多线程错误
- 多线程程序生产者/消费者[BOOST]
- 如何编译Boost多线程程序
- 多线程之谜与 Boost C++
- 我们是否需要每个线程多个io_service用于具有单个接受器的线程 boost::asio 服务器
- Boost:大图和多线程
- boost::d ynamic_bitset 多线程问题
- boost::shared_mutex与boost:,用于多线程写入的互斥
- Boost单元测试可以是多线程的吗
- 使用boost库是c++中实现多线程的正确方法
- 修复(可怕的错误)! "Assertion `px != 0' failed."聊天服务器中使用 boost、std::map 和多线程