17

假设我需要从磁盘上保存的同一个文件中读取许多不同的、独立的数据块。

这个上传可以多线程吗?

相关:同一处理器上的所有线程是否使用相同的 IO 设备从磁盘读取?在这种情况下,多线程根本不会加快上传速度——线程只会排队等待。

(我目前正在使用 OpenMP 进行多线程处理。)

4

5 回答 5

36

对的,这是可能的。然而:

同一处理器上的所有线程是否使用相同的 IO 设备从磁盘读取?

是的。磁盘上的读磁头。例如,尝试并行而不是串行复制两个文件。并行需要更长的时间,因为操作系统使用调度算法来确保两个线程/进程之间的 IO 速率是“公平的”或相等的。正因为如此,读磁头会在磁盘的不同部分之间来回跳跃,从而大大减慢了处理速度。与查找数据的时间相比,实际读取数据的时间非常短,而且当您一次读取磁盘的两个不同部分时,您大部分时间都在查找。

请注意,所有这些都假设您使用的是硬盘。如果您使用的是 SSD,并行运行速度不会变慢,但也不会变快。编辑:根据评论,SSD 的并行实际上更快。使用 RAID,情况会变得更加复杂,并且(显然)取决于您使用的 RAID 类型。

这就是它的样子(我将圆形磁盘展开成一个矩形,因为 ascii 圆圈很难,并简化了数据布局以使其更易于阅读):

假设文件被盘片上的一些空间分隔,如下所示:

|         |

系列阅读看起来像(*表示阅读)

space ----->
|        *|  t
|        *|  i
|        *|  m
|        *|  e
|        *|  |
|       / |  |
|     /   |  |
|   /     |  V
|  /      |
|*        |
|*        |
|*        |
|*        |

虽然并行读取看起来像

|       \ |
|        *|
|       / |
|     /   |
|   /     |
|  /      |
|*        |
|  \      |
|    \    |
|     \   |
|       \ |
|        *|
|       / |
|     /   |
|   /     |
|  /      |
|*        |
|  \      |
|    \    |
|     \   |
|       \ |
|        *|

ETC

于 2012-11-16T18:27:30.643 回答
8

如果您在 Windows 上执行此操作,您可能需要查看ReadFileScatter函数。它将允许您在单个异步调用中从文件中读取多个段。这将允许操作系统更好地控制文件 IO 瓶颈,并有望优化读取。

Windows 上匹配的写入调用将是WriteFileGather

对于 UNIX,您正在使用readvwritev来做同样的事情。

于 2012-11-16T18:51:06.660 回答
3

如其他答案中所述,并行读取可能会更慢,具体取决于文件物理存储在磁盘上的方式。因此,如果头部必须移动很长一段距离,则可能会导致实际减速。话虽如此,但有些存储系统可以有效地支持多个同时读取和写入。我能想象的最简单的是SSD磁盘。我本人曾使用 IBM 的出色存储系统,它可以同时执行读取和写入而不会减慢速度。因此,让我们假设您有这样一个文件系统和物理存储,在并行读取时不会减慢速度。

在这种情况下,并行读取是非常合乎逻辑的。一般来说,有两种方法可以实现:

  1. 如果您想使用标准 C/C++ 库来执行 IO,那么您唯一的选择是为每个线程保留一个打开的文件句柄(描述符)。这是因为文件指针(指向从文件中读取或写入的位置)按句柄保存。因此,如果您尝试从同一个文件句柄同时读取,您将无法知道您实际阅读的内容。
  2. 使用平台特定的 API 来执行异步 (OVERLAPPED) IO。在 Windows 上,您将 WinAPI 函数与所谓的 OVERLAPPED IO 一起使用。在 Unix/Linux 上,您有 posix AIO,尽管我知道不鼓励使用它,尽管我没有看到任何令人满意的解释来说明为什么会这样。

我自己在 linux 和 windows 上实现了 fd/thread 方法,在 windows 上实现了 OVERLAPPED 方法。两者都工作得很好。

于 2012-11-16T19:13:18.957 回答
1

您将无法加快读取磁盘的过程。如果您在写作的同时进行计算,并行化会有所帮助。但是纯粹的写入将受到处理器和硬盘驱动器之间的通道带宽的限制,更值得注意的是,受到硬盘驱动器本身的限制(我的硬盘驱动器为 30 MB/s,我听说过 120 MB/s 以上的 raid 设置网络,但不要依赖它)。

于 2012-11-16T17:50:32.377 回答
0

如果您使用标准系统功能,则从磁盘进行多次读取应该是线程安全的,如果您使用标准系统功能,则无需手动锁定它,但以只读方式打开文件。(否则你会得到文件访问错误。)

顺便说一句,您实际上不需要从磁盘读取,操作系统将决定它从哪里为您服务。它通常从内存中预取读取和服务。

于 2012-11-16T18:20:47.983 回答