多线程文件读取



我需要阅读/解析一个大的二进制文件(4〜6 GB),该文件以8192字节的固定块出现。我当前的解决方案涉及使用单个生产商多重消费者(SPMC)模式流式传输文件块。

编辑

文件大小= n * 8192字节

我要做的就是对这8192个字节中的每一个做点事。仅一旦上自上而下,才需要读取该文件。

认为这应该是一个令人尴尬的并行问题,我想拥有 x 线程以相等的范围读取(文件大小/ <em)> x )独立尺寸。线程根本不需要彼此交流。

我尝试过产卵 x 线程打开同一文件并寻求其各自的部分进行处理,但是,此解决方案似乎对此有问题HDD机械寻求并显然比SPMC解决方案更糟。

如果在SSD上使用此方法会有任何区别吗?

,或者只要存储器映射整个文件并使用#pragma omp parallel for处理块?我想我需要足够的公羊才能这样做?

您会建议什么?

您会建议什么?

不使用mmap()

per linux torvalds本人:

人们喜欢mmap()和其他使用页面表的方式 优化副本操作,有时值得。

但是,使用虚拟内存映射玩游戏非常 本身很昂贵。它具有许多非常真实的缺点 人们倾向于忽略,因为记忆复制被视为非常 缓慢,有时优化该副本被视为明显的 即兴。

MMAP的偏低:

  • 非常明显的设置和拆卸成本。我的意思是明显。 就像遵循页面表一样,可以清洁所有内容。这是保留所有
    列表的书籍 映射。拆开东西后,这是TLB冲洗所需的。
  • 页面故障很昂贵。这就是映射被人口填充的方式,而且非常慢。

mmap的效果:

  • 如果数据一遍又一遍地重复使用(在单个地图操作中),或者,如果您可以通过映射某些内容来避免许多其他逻辑,则MMAP()只是切成薄片的面包以来最大的事情。

这可能是您多次使用的文件(可执行文件的二进制图像是明显的情况 - 代码在该位置周围跳跃),或者是一个设置,在此设置非常方便地将整个内容映射到不考虑MMAP()赢得的实际用法模式。您可能具有随机访问模式,并使用MMAP()来跟踪您实际需要的数据。

  • 如果数据很大,则MMAP()是让系统知道它可以使用数据集的好方法。内核可以忘记页面,因为内存压力迫使系统将内容弄清楚,然后自动重新挑选它们。

    显然是这样的情况。

但是您的测试套件(仅复制数据)可能是对的 对于mmap()。

注意最后一个 - 仅使用数据是mmap()的不良用例。

对于SSD 上的文件,由于没有物理头部寻求运动:

  1. 打开文件一次,使用open()获取单个int文件描述符。

  2. 使用每个线程使用pread()读取适当的8KB块。pread()从指定的偏移量读取而无需使用lseek(),并且不会影响正在读取的文件的当前偏移。

您可能需要比CPU内核更多的线程,因为每个线程都会有重要的IO。

对于机械磁盘上的文件:

您想最大程度地减少机械磁盘上的头部搜索。

使用open()与Direct IO(假设Linux,open( filename, O_RDONLY | O_DIRECT );)打开一次文件,以绕过页面缓存(因为您将要流式传输文件,并且永远不会重新阅读其任何部分在这里很好)

  1. 使用单个生产者线程,读取大块(例如64K至1MB )进入n页对准的缓冲区之一。
  2. 读取缓冲区时,将其传递给工作人员线程,然后阅读以填充下一个缓冲区

  3. 当所有工人都使用缓冲区的一部分完成时,请通过缓冲区回到阅读线程。

您需要尝试使用适当的read()大小,工作线数量和缓冲区的数量。较大的read() S将更有效,但是较大的缓冲尺寸使内存要求更大,并使从工作线程中获得缓冲区的延迟更加不可预测。您想制作尽可能少的数据副本,因此您希望工作线程直接在文件中读取的缓冲区。

即使每个8K块的处理都很重要(OCR处理缺乏),I/O也是瓶颈。除非可以安排该文件的一部分已经被以前的操作缓存..

如果要运行的系统可以解决问题:

  1. 获取文件大小(fstat
  2. 分配一个大小的缓冲区。
  3. 打开并将整个文件读取到缓冲区中。
  4. 弄清楚如何分区每个线程的数据并旋转线程。
  5. 算法的时间

然后,使用异步读数对其进行修改。请参阅man aio_readman 7 aio以了解需要完成的操作。

最新更新