我的应用程序中有一个包含大量信息的输入文件。按顺序读取它,并且一次只有一个文件偏移量对于我的应用程序的使用是不够的。理想情况下,我希望有两个线程,它们具有从同一文件的两个唯一文件偏移量中分离且不同的ifstream
读取。我不能只启动一个ifstream
,然后使用它的复制构造函数复制它(因为它是不可复制的)。 那么,我该如何处理呢?
我可以立即想到两种方式,
ifstream
,在同一个文件上打开它。ifstream
的单个实例(使用例如boost::shared_ptr<>
)。当线程获得时间片时,寻找当前线程当前感兴趣的适当文件偏移量。这两种方法中的一种是首选吗?
我还没有想到第三个(或第四个)选项吗?
显然,我最终受限于硬盘驱动器必须来回旋转,但我感兴趣的是(如果可能的话),同时在两个文件偏移处都有一些操作系统级磁盘缓存。
感谢。
答案 0 :(得分:9)
这里有两个std::ifstream
实例可能是最好的选择。现代硬盘驱动器针对大量I / O请求进行了优化,因此同时从两个std::ifstream
实例读取应该可以提供相当不错的性能。
如果你有一个std::ifstream
,你将不得不担心同步对它的访问,加上它可能会破坏操作系统的自动顺序访问预读缓存,导致性能下降。
答案 1 :(得分:6)
在两者之间,我宁愿第二个。对同一文件进行两次打开可能会导致文件之间的视图不一致,具体取决于底层操作系统。
对于第三个选项,将引用或原始指针传递给另一个线程。只要语义是一个线程“拥有”istream,原始指针或引用都可以。
最后请注意,在绝大多数硬件上,加载大文件时磁盘是瓶颈,而不是CPU。使用两个线程会使更糟,因为您正在将顺序文件访问转变为随机访问。典型的硬盘可以按顺序执行100MB / s,但最高可达3或4 MB / s随机访问。
答案 2 :(得分:4)
其他选择:
istrstream
对此有好处,istringstream
不是。)答案 3 :(得分:1)
这取决于你的系统。现代系统通常会阅读 先;在文件中寻找可能会抑制这一点,所以应该 绝对要避免。
可能值得尝试预读如何在您的系统上运行:
打开文件,然后按顺序读取它的前半部分,看看如何
需要很长时间。然后打开它,寻找中间,然后阅读第二个
半顺序。 (在我过去看过的一些系统上,很简单
寻求,在任何时候,将关闭预读。)最后,打开它,然后
读取所有其他记录;这将使用相同的模拟两个线程
文件描述符。 (对于所有这些测试,使用固定长度记录,和
以二进制模式打开。还要采取必要的步骤来确保
以前从文件的缓存中清除文件中的任何数据
开始测试 - 在Unix下,复制10或20千兆字节的文件
到/dev/null
通常就足够了。
这会给你一些想法,但要确定,最好的
解决方案是测试真实案例。如果分享一个,我会感到惊讶
单ifstream
(因而是单个文件描述符),并且不断
寻求,赢了,但你永远不知道。
我还推荐像mmap
这样的系统特定解决方案,但如果你这样做的话
获得了那么多数据,很有可能你无法映射它
无论如何都要一气呵成。 (您仍然可以使用mmap
映射部分
一次,但它变得更加复杂。)
最后,是否可以将数据分成几部分 较小的文件?这可能是所有人中最快的解决方案。 (理想情况下, 这将在数据生成或导入数据的地方完成 系统。)
答案 4 :(得分:0)
我的投票将是一个读者,它将数据交给多个工作线程。
如果您的文件位于单个磁盘上,则多个读取器将终止您的读取性能。是的,你的内核可能有一些很棒的缓存或排队功能,但它会花费更多的时间来阅读数据。