使用ifstream在两个线程中处理相同的文件

时间:2011-06-02 15:25:45

标签: c++ multithreading io fstream ifstream

我的应用程序中有一个包含大量信息的输入文件。按顺序读取它,并且一次只有一个文件偏移量对于我的应用程序的使用是不够的。理想情况下,我希望有两个线程,它们具有从同一文件的两个唯一文件偏移量中分离且不同的ifstream读取。我不能只启动一个ifstream,然后使用它的复制构造函数复制它(因为它是不可复制的)。 那么,我该如何处理呢?

我可以立即想到两种方式,

  1. 为第二个线程构建一个新的ifstream,在同一个文件上打开它。
  2. 跨两个线程共享一个开放ifstream的单个实例(使用例如boost::shared_ptr<>)。当线程获得时间片时,寻找当前线程当前感兴趣的适当文件偏移量。
  3. 这两种方法中的一种是首选吗?

    我还没有想到第三个(或第四个)选项吗?

    显然,我最终受限于硬盘驱动器必须来回旋转,但我感兴趣的是(如果可能的话),同时在两个文件偏移处都有一些操作系统级磁盘缓存。

    感谢。

5 个答案:

答案 0 :(得分:9)

这里有两个std::ifstream实例可能是最好的选择。现代硬盘驱动器针对大量I / O请求进行了优化,因此同时从两个std::ifstream实例读取应该可以提供相当不错的性能。

如果你有一个std::ifstream,你将不得不担心同步对它的访问,加上它可能会破坏操作系统的自动顺序访问预读缓存,导致性能下降。

答案 1 :(得分:6)

在两者之间,我宁愿第二个。对同一文件进行两次打开可能会导致文件之间的视图不一致,具体取决于底层操作系统。

对于第三个选项,将引用或原始指针传递给另一个线程。只要语义是一个线程“拥有”istream,原始指针或引用都可以。

最后请注意,在绝大多数硬件上,加载大文件时磁盘是瓶颈,而不是CPU。使用两个线程会使更糟,因为您正在将顺序文件访问转变为随机访问。典型的硬盘可以按顺序执行100MB / s,但最高可达3或4 MB / s随机访问。

答案 2 :(得分:4)

其他选择:

  • 内存映射文件,根据需要创建任意数量的内存istream对象。 (istrstream对此有好处,istringstream不是。)

答案 3 :(得分:1)

这取决于你的系统。现代系统通常会阅读 先;在文件中寻找可能会抑制这一点,所以应该 绝对要避免。

可能值得尝试预读如何在您的系统上运行: 打开文件,然后按顺序读取它的前半部分,看看如何 需要很长时间。然后打开它,寻找中间,然后阅读第二个 半顺序。 (在我过去看过的一些系统上,很简单 寻求,在任何时候,将关闭预读。)最后,打开它,然后 读取所有其他记录;这将使用相同的模拟两个线程 文件描述符。 (对于所有这些测试,使用固定长度记录,和 以二进制模式打开。还要采取必要的步骤来确保 以前从文件的缓存中清除文件中的任何数据 开始测试 - 在Unix下,复制10或20千兆字节的文件 到/dev/null通常就足够了。

这会给你一些想法,但要确定,最好的 解决方案是测试真实案例。如果分享一个,我会感到惊讶 单ifstream(因而是单个文件描述符),并且不断 寻求,赢了,但你永远不知道。

我还推荐像mmap这样的系统特定解决方案,但如果你这样做的话 获得了那么多数据,很有可能你无法映射它 无论如何都要一气呵成。 (您仍然可以使用mmap映射部分 一次,但它变得更加复杂。)

最后,是否可以将数据分成几部分 较小的文件?这可能是所有人中最快的解决方案。 (理想情况下, 这将在数​​据生成或导入数据的地方完成 系统。)

答案 4 :(得分:0)

我的投票将是一个读者,它将数据交给多个工作线程。

如果您的文件位于单个磁盘上,则多个读取器将终止您的读取性能。是的,你的内核可能有一些很棒的缓存或排队功能,但它会花费更多的时间来阅读数据。