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

Process same file in two threads using ifstream

本文关键字:线程 处理 同一个 文件 两个 ifstream 使用      更新时间:2023-10-16

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

我立刻想到两种方法,

  1. 为第二个线程构造一个新的ifstream,在同一个文件上打开它
  2. 在两个线程之间共享打开的ifstream的单个实例(例如使用boost::shared_ptr<>)。当线程获得时间片时,查找当前线程当前感兴趣的适当文件偏移量

是否首选这两种方法之一

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

很明显,我最终受到了硬盘必须来回旋转的限制,但我感兴趣的是(如果可能的话)在两个文件偏移量上同时进行一些操作系统级别的磁盘缓存。

谢谢。

两个std::ifstream实例可能是这里的最佳选择。现代HDD针对大量I/O请求进行了优化,因此同时从两个std::ifstream实例中读取应该会提供相当好的性能。

如果您有一个std::ifstream,您将不得不担心同步对它的访问,此外,它可能会破坏操作系统的自动顺序访问预读缓存,从而导致较差的性能。

在两者之间,我更喜欢第二种。根据底层操作系统的不同,打开两个相同文件可能会导致文件之间的视图不一致。

对于第三个选项,将引用或原始指针传递到另一个线程中。只要语义是一个线程"拥有"istream,原始指针或引用就可以了。

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

其他选项:

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

这实际上取决于您的系统。一个现代系统通常会读向前地在文件中查找可能会抑制这种情况,因此应该一定要避免。

预读在您的系统中的工作方式可能值得一试:打开文件,然后按顺序读取它的前半部分,看看如何这需要很长时间。然后打开它,找中间,读第二个半顺序。(在我过去见过的一些系统上seek在任何时候都将关闭预读。)最后,打开它,然后每隔一条记录读取一次;这将模拟使用相同的两个线程文件描述符。(对于所有这些测试,使用固定长度的记录,以及以二进制模式打开。同时采取一切必要措施确保文件中的任何数据在开始测试—在Unix下,复制10或20 GB的文件到CCD_ 11通常就足够了。

这会给你一些想法,但可以肯定的是,最好的解决方案是测试真实的案例。如果分享单个ifstream(因此是单个文件描述符),并且寻求,赢得,但你永远不会知道。

我也推荐像mmap这样的系统特定解决方案,但如果您有那么多数据,你很有可能无法绘制地图总之,一气呵成。(您仍然可以使用mmap,映射它的部分一次,但它变得复杂得多。)

最后,是否有可能将已经切割成的数据更小的文件?这可能是最快的解决方案。(理想地,这将在生成数据或将数据导入系统。)

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

如果你的文件在一个磁盘上,那么多个读卡器会影响你的读取性能。是的,您的内核可能有一些出色的缓存或排队功能,但它将花费更多的时间来寻找而不是读取数据。