多线程从磁盘读取
multithread read from disk?
假设我需要从保存在磁盘上的同一文件中读取许多不同的、独立的数据块。
可以多线程上传吗?
相关:同一处理器上的所有线程是否使用相同的IO设备从磁盘读取?在这种情况下,多线程根本不会加快上传速度——线程只是在排队等待。
(我目前正在使用OpenMP进行多线程处理。)
是的,这是可能的。但是:
同一处理器上的所有线程是否使用相同的IO设备从磁盘读取?
是。磁盘上的读取头。例如,尝试并行复制两个文件,而不是串行复制。这将需要更长的并行时间,因为操作系统使用调度算法来确保两个线程/进程之间的IO速率"公平"或相等。正因为如此,读取头将在磁盘的不同部分之间来回跳跃,从而大大减慢处理速度。与查找数据的时间相比,实际读取数据的时间非常短,而且当您同时读取磁盘的两个不同部分时,大部分时间都在查找。
请注意,所有这些都假设您使用的是硬盘如果你使用的是SSD,它在并行时不会更慢,但也不会更快Edit:根据评论,并行实际上对SSD来说更快。有了RAID,情况会变得更加复杂,而且(显然)取决于您使用的RAID类型。
这就是它的样子(我把圆盘展开成一个矩形,因为ascii圆很硬,并简化了数据布局,使其更容易阅读):
假设文件被盘片上的一些空间隔开,如下所示:
| |
序列读取将看起来像(*
表示读取)
space ----->
| *| t
| *| i
| *| m
| *| e
| *| |
| / | |
| / | |
| / | V
| / |
|* |
|* |
|* |
|* |
而并行读取看起来像
| |
| *|
| / |
| / |
| / |
| / |
|* |
| |
| |
| |
| |
| *|
| / |
| / |
| / |
| / |
|* |
| |
| |
| |
| |
| *|
etc
如果您在Windows上执行此操作,您可能需要研究ReadFileScatter函数。它将允许您在单个异步调用中读取文件中的多个段。这将允许操作系统更好地控制文件IO瓶颈,并有望优化读取。
Windows上匹配的写入调用将是WriteFileGather。
对于UNIX,您正在考虑readv和writev来做同样的事情。
如其他答案中所述,根据文件在磁盘上的物理存储方式,并行读取可能会较慢。因此,如果头部必须移动相当长的距离,可能会导致实际的减速。也就是说,存在可以有效地支持多个同时读取和写入的存储系统。我能想到的最简单的就是一个固态硬盘。我自己使用的是IBM的出色存储系统,它可以同时执行读写操作,而且速度不会减慢。因此,让我们假设您有这样一个文件系统和物理存储,它不会降低并行读取的速度。
在这种情况下,并行读取是非常合乎逻辑的。一般来说,有两种方法可以实现这一点:
- 如果您想使用标准的C/C++库来执行IO,那么您唯一的选择就是为每个线程保留一个打开的文件句柄(描述符)。这是因为文件指针(指向文件中的读写位置)是按句柄保存的。因此,如果你试图同时从同一个文件句柄中读取,你将无法知道你实际读取的内容
- 使用特定于平台的API来执行异步(OVERLAPPED)IO。在windows上,您使用WinAPI函数和所谓的OVERLAPPEDIO。在Unix/Linux上,您有posix AIO,尽管我知道不鼓励使用它,但我没有看到任何令人满意的解释来解释为什么会出现这种情况
我自己在linux和windows上都实现了fd/线程方法,在windows上实现了OVERLAPPED方法。两者都很好。
您将无法加快向磁盘读取的过程。如果你在写作的同时进行计算,那么并行化会有所帮助。但是,纯粹的写入将受到处理器和硬盘驱动器之间通道带宽的限制,更值得注意的是,受到硬盘驱动器本身的限制(我的硬盘驱动器有30MB/s,我听说过为120服务的突袭设置MB/s,但不要依赖于此)。
根据操作系统的设计,从磁盘进行多次读取应该是线程安全的。如果您使用标准的系统功能,则无需手动锁定,但以只读方式打开文件。(否则会出现文件访问错误。)
顺便说一句,如果你在实践中不需要从磁盘上读取,操作系统将决定从哪里为你提供服务。它通常从内存中预取读取和服务。
- 如何将 numpy 二维数组作为一种可以用C++读取的二进制格式存储在磁盘上
- 是否可以使用 Webassembly 从磁盘读取文件?
- C++ 从磁盘读取文件并将其写入共享内存
- 如何在 Ubuntu 上提高我的程序磁盘读取速度
- 如何在C++中读取/写入大文件时减少 I/O 磁盘访问次数
- 多线程从磁盘读取
- 如何使用ATA命令通过DeviceIocontrol Funtion读取大磁盘(例如1,2 TB)
- 如何使用ATA命令读取磁盘的特定扇区
- 在从磁盘写入和读取的结构中使用std::bitset可以吗
- 每次需要时,将整个文件从磁盘复制到内存中,以处理或读取文件中的数据,直到文件全部读取
- 从文件读取磁盘部分时出错
- 缓冲的 std::ifstream 只能从磁盘读取一次 (C++)
- 是否可以使用脚本或程序强制从磁盘上读取受保护的文件
- 如何逐位读取整个磁盘的内容
- 在编译器之间读取和写入原始对象到磁盘(istream)
- HDF5在磁盘上将32位无符号int写入64位,并读取32位无信号int
- 从磁盘读取映像文件出错
- 如果一个程序的主要功能是从磁盘中读取数据,那么让它多线程是不是一个好主意?
- 如何在C变量中读取磁盘使用情况(du)
- 使用std::ifstream强制读取磁盘,而不是文件缓存