【问题标题】:multithread read from disk?多线程从磁盘读取?
【发布时间】:2012-11-05 11:37:00
【问题描述】:

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

这个上传可以多线程吗?

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

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

【问题讨论】:

  • 多个线程可以同时读取,通常需要多个线程(或进程)进行 IO 才能使单向带宽饱和。当然,从一个非常大的文件的遥远部分读取可能(并且大多数情况下)会使磁盘磁头不断寻找。
  • @HristoIliev 除非系统预取更大的块。

标签: c++ multithreading io openmp


【解决方案1】:

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

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

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

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

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

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

|         |

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

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

虽然并行读取看起来像

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

【讨论】:

  • 基本正确,但您正在假设操作系统如何在磁盘上放置文件(或者甚至是 HD 本身如何在物理介质上放置扇区)。 SSD 的搜索也是“免费的”。 IO 管道将以最低组件的速度运行,网络上传很可能是网络。
  • 亲爱的@Dan - 如果我将“从文件读取”部分包装在“关键区域”中,例如#pragma omp critical { read_from_disk();这会减轻对读头的需求吗?这基本上相当于没有这部分有并行代码,对吧?
  • 基准测试 - 使用 1M 读取从硬盘读取 7 个 1.5GB 的文件并对其进行 sha512 处理,1 个线程的速度为 100MB/s,8 个线程的速度为 50MB/s。从 SSD 得出 1 个线程 150MB/s,8 个线程 500MB/s。
【解决方案2】:

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

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

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

【讨论】:

  • unix 也有readvman page
  • @Dan 很高兴知道,将其添加到答案中。 :)
  • 忘记了这个 API 真是太好了 - 虽然这不能解决覆盖线程的要求 (+1)
  • 我不认为这实际上优化了读取。两个 API 都会按照给定的顺序填充缓冲区。
【解决方案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 方法。两者都很好用。

【讨论】:

    【解决方案4】:

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

    【讨论】:

    • (编辑:写作同样适用于阅读,误读问题,所以交换写作阅读。)
    • 好的...所以您的答案是...多个线程可以同时从磁盘读取?
    • 可以,但不会加快速度。
    【解决方案5】:

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

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

    【讨论】:

      猜你喜欢
      • 2020-04-14
      • 2018-06-29
      • 1970-01-01
      • 2016-04-26
      • 2011-02-11
      • 1970-01-01
      • 2011-10-04
      • 2015-07-19
      • 1970-01-01
      相关资源
      最近更新 更多