c++ - 在一个大文件上进行许多小的盲写的最快方法(在 C++ 中)?

标签 c++ performance file-io

我有一些非常大 (>4 GB) 的文件,其中包含(数百万)固定长度的二进制记录。我想(有效地)通过将指针(即 64 位记录编号)写入特定偏移量的记录中,将它们连接到其他文件中的记录。

为了详细说明,我有一对(键,记录号)元组列表,对于我想对给定文件对(例如 A 和 B)执行的每个连接,键排序。遍历列表对并匹配向上键产生一个(键,记录号 A,记录号 B)表示连接记录的元组列表(为简单起见假设 1:1 映射)。为了完成连接,我在概念上需要查找列表中的每个 A 记录,并在适当的偏移处写入相应的 B 记录号,反之亦然。我的问题是实际执行此操作的最快方法是什么?

由于连接记录的列表是按键排序的,因此关联的记录编号基本上是随机的。假设文件比操作系统磁盘缓存大得多,进行一堆随机查找和写入似乎效率极低。我尝试通过将 A->B 和 B->A 映射放在稀疏数组中来部分排序记录号,并在内存不足时将最密集的条目簇刷新到磁盘。这样做的好处是大大增加了在更新其第一个指针后为集群缓存适当记录的机会。然而,即使在这一点上,进行一堆查找和盲写通常更好,还是手动读取文件 block ,更新适当的指针,然后将 block 写回?虽然前一种方法要简单得多,并且可以由操作系统进行优化以执行最少的扇区读取(因为它知道扇区大小)和复制(它可以通过直接读入正确对齐的缓冲区来避免复制),但它似乎将招致极高的系统调用开销。

虽然我喜欢可移植的解决方案(即使它依赖于广泛使用的库,例如 Boost),但现代 Windows 和 Linux 是唯一必备的,因此我可以使用特定于操作系统的 API (例如 CreateFile 提示或分散/聚集 I/O)。但是,这可能需要大量工作才能尝试,所以我想知道是否有人可以告诉我这是否值得付出努力。

最佳答案

看起来你可以通过使用数据结构来解决这个问题。你有三个约束:

  • 访问时间必须相当快
  • 数据必须保持有序
  • 你在一个旋转的圆盘上

B+ Trees专为解决您在这里处理的工作负载而创建。链接的维基百科文章中有几个指向实现的链接。

本质上,B+ 树是一种二叉搜索树,除了节点组以组的形式聚集在一起。这样,B+ 树就不必四处寻找每个节点,一次只加载一个 block 。它保留了一些信息,以了解在搜索中需要哪个 block 。

编辑:如果您需要按多个项目排序,您可以这样做:


+--------+-------------+-------------+---------+
| Header | B+Tree by A | B+Tree by B | Records |
+--------+-------------+-------------+---------+
      ||      ^     |     ^    |          ^
      |\------/     |     |    |          |
      \-------------------/    |          |
                    |          |          |
                    \----------+----------/

即每个键都有单独的 B+ 树,还有一个单独的记录列表,指向这些记录的指针存储在 B+ 树中。

关于c++ - 在一个大文件上进行许多小的盲写的最快方法(在 C++ 中)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3216494/

相关文章:

java - 打开文件读取Numbers并将其添加到链接列表中

c++ - 如何在 C++ 中正确访问继承的方法和构造函数?

c++ - Clion——为什么我需要输入完整路径?

javascript - Safari 和 Firefox 上的视差/translate3d 性能问题?

java - 内部 JAR 使用文件系统上的文件

javascript - 应用程序重新启动后追加到文件 - Phonegap

c++ - 组织具有部分共享接口(interface)的对象

c++ - 为一个项目使用超过 1 个代码文件有什么好处? (C++)

c++ - 我如何计算 C++ 中的操作?

jquery - 在 jQuery 中将数据属性提取为数组的最简单方法?