Boost r-tree 在内存与映射文件中的性能差异

Posted

技术标签:

【中文标题】Boost r-tree 在内存与映射文件中的性能差异【英文标题】:Performance difference of Boost r-tree in memory vs. mapped file 【发布时间】:2015-01-30 08:28:19 【问题描述】:

我需要创建一个 3D R*-tree,也许是为了长时间存储,但性能也是一个问题。 为了创建树,我决定使用 Boost 的 spacialindex,基本上找到了两种可能的方法。

我要么直接使用对象创建它,因为它在这里:Index of polygons stored in vector,但是这不允许我在不再次创建 R*-tree 的情况下存储和加载它。

或者我可以使用此处解释的映射文件:Index stored in mapped file using Boost.Interprocess,但是,我不确定在这种情况下查询的性能是否足够好。

我的 r-tree 将包含数千个条目,但很可能少于 100,000 个。现在我的问题是,与使用标准对象相比,使用映射文件是否存在任何强大的性能问题?此外,如果创建大约 100,000 个值的 R*-tree 不需要花费大量时间(我可以将所有边界框和相应的键/数据存储在一个文件中),那么跳过映射文件并在每次运行程序时创建树?

希望有人可以在这里帮助我,因为文档并没有真正提供太多信息(尽管它仍然比 libspacialindex 的文档更好)。

【问题讨论】:

【参考方案1】:

映射文件的行为主要类似于常规内存(事实上,在 Linux 中,newmalloc 的内存分配将使用 mmap [带有“无文件”后备存储]作为底层分配方法) .但是,如果您“到处”进行许多小写入,并且您正在映射一个真实文件,那么操作系统将在写入文件之前限制缓冲写入的数量。

我在不久前提出这个主题时做了一些实验,通过调整操作系统如何处理这些“挂起的写入”的设置,即使对于具有随机读/写模式的文件备份内存映射,我也获得了合理的性能 [something我希望在您构建树时发生]。

这是“随机写入的 mmap 性能”问题,我认为这是高度相关的: Bad Linux Memory Mapped File Performance with Random Access C++ & Python (这个答案适用于 Linux - 其他操作系统,尤其是 Windows,在处理对映射文件的写入方面可能表现完全不同)

当然,很难说“哪个更好”,在内存映射文件或每次程序运行时重新构建之间 - 这实际上取决于您的应用程序做什么,是每秒运行 100 次还是一次一天,重建需要多长时间[我完全不知道!],以及许多其他类似的事情。有两种选择:构建最简单的版本,看看它是否“足够快”,或者构建两个版本,然后测量有多少差异,然后决定走哪条路。

我倾向于构建简单(ish)的模型,如果性能不够好,找出慢的原因,然后修复它 - 这样可以节省大量时间来制作需要 0.01% 的东西总执行时间快了 5 个时钟周期,最终在其他地方产生了一个大想法,使其运行速度比您预期的慢 500 倍......

【讨论】:

感谢您的快速回答。你当然是对的,这完全取决于程序的使用,不幸的是,如果你在一个更大的项目中工作,而且还不确定我的部分将如何被准确使用,在我必须完成之前我可能不知道。感谢您指出您的性能测试,我会看看它。如果没有人(例如创建这个库的 Adam Wulkiewicz)回答,我会接受你的。这可能不是对我的问题的确切答案,但涵盖了该主题。 这个答案还不错,但是太具体了,因为 OP 没有指明他的操作系统,所有真实内容仅适用于 Linux。 我已将我的操作系统添加到标签中!感谢您指出。 @Puppy:指出这种性能分析是“仅限 linux”,但我不知道除了“刷新写入”是缓慢的原因之外的任何其他原因 - 当然,Windows 可能不会对此进行调整......或者你真的知道在其他一些操作系统中“映射文件的行为不像常规内存”的原因吗? 另外,如果您正在构建一个要集成到另一个更大程序中的模块,那么谨慎尝试确定您的模块的性能是否“超级关键,因为它正在被使用每次你做 X 时,X 在我们的系统中很常见”,或者“不是那么重要,因为它每天只发生一次,这种情况下的延迟不是太严重”[注意“很少发生”确实并不是真的意味着“对性能不重要”——在汽车系统中,防抱死刹车应该“快速”工作,即使不经常启动发动机“无关紧要”【参考方案2】:

批量加载索引比重复插入要快得多,并且会产生更高效的树。因此,如果您可以将所有数据保存在主内存中,我建议使用 STR 批量加载重建树。以我的经验,这已经足够快了(批量加载时间与 I/O 时间相比相形见绌)。

STR 的成本大致相当于排序的成本。 O(n log n) 理论上,具有非常低的常数(效率较低的实现可能是 O(n log n log n),但仍然相当便宜)。

【讨论】:

感谢您的回复。我最初想实现打包算法,但找不到如何创建树。除了 bgi::rstar、bgi::linear 和 bgi::quadratic,我没有找到其他任何东西(bgi = boost::geometry::index)。另外,这究竟如何解决我的存储等问题? 我没用过bgi,所以不知道有没有这个功能。但它比完整的 R* 树更容易实现,所以如果它们没有批量加载,我会感到惊讶。批量加载很便宜,我认为您不需要存储树。 谢谢,我会调查一下,如果我还能找到它。是的,如果无论如何快速创建树,那么我不需要存储它并且每次都创建它,这样更新数据也可能更容易,只需向文件添加带有键的附加边界框。

以上是关于Boost r-tree 在内存与映射文件中的性能差异的主要内容,如果未能解决你的问题,请参考以下文章

在 Linux 上是不是将 boost 内存映射文件归零

使用 C++ boost 库如何创建两个圆圈并将它们添加到 boost R-tree?

RAM 磁盘与 Boost 进程间通信

作者推荐 | Java难点攻克「NIO和内存映射性能提升系列」彻底透析NIO底层的内存映射机制原理与Direct Memory的关系

R-trees 上的多级查询(交集、联合)

24 基于mmap内存映射实现磁盘文件的高性能读写