【问题标题】:Several ifstreams vs. ifstream + constant seeking几个 ifstream 与 ifstream + 不断寻找
【发布时间】:2026-01-25 05:10:02
【问题描述】:

我正在编写一个外部合并排序。它的工作原理是这样的:从大文件中读取 k 个块,在内存中对它们进行排序,执行 k 路合并,完成。所以我需要在 k 路合并阶段从文件的不同部分顺序读取。最好的方法是什么:几个 ifstream 或一个 ifstream 和寻找?另外,有没有简单的异步 IO 库?

【问题讨论】:

  • 我认为 fstream 一个简单的异步 IO 库:-)
  • @Cameron 除了不是异步的
  • @Neil:对不起,你是对的,我设法将异步与随机访问混淆了。我需要更多的睡眠!

标签: c++ ifstream external-sorting


【解决方案1】:

在同一文件上一次使用一个ifstream。不止一个会浪费资源,而且无论如何你都必须寻找(因为默认情况下ifstream 的文件指针从文件开头开始)。

关于 C++ 异步 IO 库,请查看 this question

编辑:我最初误解了您要做什么(这个Wikipedia article 填写了我)。我不知道默认有多少ifstream缓冲,但是你可以使用pubsetbuf(0, 0);方法described here关闭缓冲,然后自己做缓冲。但是,这可能比使用多个带有自动缓冲的ifstreams 慢。一些基准测试是有序的。

【讨论】:

  • 您不必“无论如何都必须寻找”,因为对于多个流,您对文件的每个块 (k) 进行一次寻找。使用单个流进行多路合并,每个合并的项目大约进行一次搜索 (n),尽管如果长时间运行的项目来自单个块,您可能会很幸运。但是,如果数据最初是随机顺序的,那么这种可能性可以忽略不计。
【解决方案2】:

一定要尝试多个流。寻找可能会丢弃内部缓冲的数据(至少在进程内,即使操作系统将其保留在缓存中),如果您正在排序的项目很小,这确实可能非常昂贵。

无论如何,比较两种 fstream 策略的性能应该不会太难。用 k = 2 做一个简单的实验。

请注意,一个进程可以同时打开的文件数量可能存在限制 (ulimit -n)。如果达到了,那么您可能需要考虑使用单个流,但手动缓冲来自每个 k 块的数据。

如果文件足够小(相当于:您的地址空间足够大),可能值得映射文件并使用多个指针。

【讨论】:

  • 打开文件或打开文件流的数量是否有限制(我只需要访问 1 个文件,但有很多文件流)?不幸的是,文件大小远远大于内存大小。外部排序正是如此。
  • 可能是流媒体,但我不确定。当 *NIX 说“打开的文件”时,我相信这意味着文件描述符的数量而不是它们指向的不同文件的数量。我提到 mmap 是因为它不需要文件适合内存,只需给它一个地址范围(在您的 32 位或 64 位虚拟地址空间内)。然后,操作系统会在使用物理 RAM 时将文件的各个部分分页进出物理 RAM。