C++ 使用ifstream在两个线程中处理相同的文件
我的应用程序中有一个包含大量信息的输入文件。按顺序读取,并且一次只读取一个文件偏移量,对于我的应用程序的使用是不够的。理想情况下,我希望有两个线程,它们从同一文件的两个唯一文件偏移量中读取独立且不同的C++ 使用ifstream在两个线程中处理相同的文件,c++,multithreading,io,fstream,ifstream,C++,Multithreading,Io,Fstream,Ifstream,我的应用程序中有一个包含大量信息的输入文件。按顺序读取,并且一次只读取一个文件偏移量,对于我的应用程序的使用是不够的。理想情况下,我希望有两个线程,它们从同一文件的两个唯一文件偏移量中读取独立且不同的ifstreams。我不能只启动一个ifstream,然后使用它的复制构造函数复制它(因为它是不可复制的)那么,我该如何处理呢? 我马上想到两种方法 为第二个线程构造一个新的ifstream,在同一个文件中打开它 跨两个线程共享打开的ifstream的单个实例(例如使用boost::shared_p
ifstream
s。我不能只启动一个ifstream
,然后使用它的复制构造函数复制它(因为它是不可复制的)那么,我该如何处理呢?
我马上想到两种方法
ifstream
,在同一个文件中打开它ifstream
的单个实例(例如使用boost::shared_ptr
)。当线程获得时间片时,查找当前线程当前感兴趣的适当文件偏移量谢谢。在两者之间,我更喜欢第二种。同一个文件有两个开口可能会导致文件之间的视图不一致,具体取决于底层操作系统 对于第三个选项,将引用或原始指针传递到另一个线程。只要语义是一个线程“拥有”istream,原始指针或引用就可以了
最后请注意,在绝大多数硬件上,加载大型文件时,磁盘是瓶颈,而不是CPU。使用两个线程会使情况变得更糟,因为您正在将顺序文件访问转变为随机访问。典型的硬盘可以按顺序执行100MB/s的访问,但随机访问速度最高可达3Mb/s或4Mb/s。两个
std::ifstream
实例可能是最佳选择。现代HDD针对大量I/O请求进行了优化,因此同时读取两个std::ifstream
实例应该会提供相当好的性能
如果您只有一个std::ifstream
,您将不得不担心对它的同步访问,而且它可能会破坏操作系统的自动顺序访问预读缓存,从而导致性能下降。其他选项:
- 内存映射文件,创建任意多个内存istream对象。(
对此很好,istrstream
则不然)istringstream
- 我的投票将是一个读卡器,它将数据交给多个工作线程
如果您的文件位于单个磁盘上,那么多个读卡器将降低您的读取性能。是的,您的内核可能具有一些出色的缓存或排队功能,但它将花费更多的时间来查找而不是读取数据。这实际上取决于您的系统。现代制度通常是 向前地在文件中查找可能会抑制这种情况,因此应该 肯定要避免 可能值得在您的系统上尝试预读的工作方式: 打开文件,然后按顺序读取前半部分,然后查看如何读取 这需要很长时间。然后打开它,找中间,读第二个 半连续的。(在我过去见过的一些系统上,一个简单的 seek在任何时候都将关闭预读。)最后,打开它,然后 每读一次记录;这将使用相同的方法模拟两个线程 文件描述符。(对于所有这些试验,使用固定长度记录,以及 以二进制模式打开。同时采取任何必要步骤确保 文件中的任何数据在 在Unix下启动测试,复制10或20 GB的文件 对于这一点,使用
/dev/null
通常就足够了
这会给你一些想法,但确实是最好的
解决方案是测试真实案例。如果共享一个
单个ifstream
(因此是单个文件描述符),并且持续
追求,赢得,但你永远不知道
我还推荐系统特定的解决方案,如mmap
,但如果您
有那么多数据,你很有可能无法绘制它
不管怎样,都可以一次完成。(您仍然可以使用mmap
,映射它的各个部分。)
有时,但它会变得复杂得多。)
最后,是否有可能将数据分割成
较小的文件?这可能是最快的解决方案。(理想情况下,
这将在生成数据或将数据导入到
系统。)注意他用“<代码> STD::IFSturis/Cuff>”来读取文件。在这种情况下,他不必担心不一致的视图。@科丽:在这种特殊情况下,这是正确的。我在更一般地思考。编译器是否需要支持某个C++标准来使用这个?@ JT:内存映射没有被标准覆盖。您必须对我们进行监视。在POSIX上,它将是
mmap
,在Windows上,它将是CreateFileMapping
+MapViewOfFile
内存映射不是标准的一部分。不过,Boost Interprocess支持跨平台内存映射。我想?@awoodland:是的。在C++0x中,它也被弃用。Since deprecated意味着“需要出现在任何一致的实现中”,我们可以这样做;-)另一种方法是重写代码,直接在映射数组上操作,而不是通过流,但是使用istrstream
(必须是只读的)是非常无害的。只有在原始访问是随机的情况下,这才是正确的。如果最初的访问是顺序的,那么由两个线程引起的随机访问将使情况变得更糟。他明确表示,按顺序阅读是不够的。