我需要阅读/解析一个大的二进制文件(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 上的文件,由于没有物理头部寻求运动:
-
打开文件一次,使用
open()
获取单个int
文件描述符。 -
使用每个线程使用
pread()
读取适当的8KB块。pread()
从指定的偏移量读取而无需使用lseek()
,并且不会影响正在读取的文件的当前偏移。
您可能需要比CPU内核更多的线程,因为每个线程都会有重要的IO。
对于机械磁盘上的文件:
您想最大程度地减少机械磁盘上的头部搜索。
使用open()
与Direct IO(假设Linux,open( filename, O_RDONLY | O_DIRECT );
)打开一次文件,以绕过页面缓存(因为您将要流式传输文件,并且永远不会重新阅读其任何部分在这里很好)
- 使用单个生产者线程,读取大块(例如64K至1MB )进入n页对准的缓冲区之一。
-
读取缓冲区时,将其传递给工作人员线程,然后阅读以填充下一个缓冲区
-
当所有工人都使用缓冲区的一部分完成时,请通过缓冲区回到阅读线程。
您需要尝试使用适当的read()
大小,工作线数量和缓冲区的数量。较大的read()
S将更有效,但是较大的缓冲尺寸使内存要求更大,并使从工作线程中获得缓冲区的延迟更加不可预测。您想制作尽可能少的数据副本,因此您希望工作线程直接在文件中读取的缓冲区。
即使每个8K块的处理都很重要(OCR处理缺乏),I/O也是瓶颈。除非可以安排该文件的一部分已经被以前的操作缓存..
如果要运行的系统可以解决问题:
- 获取文件大小(
fstat
) - 分配一个大小的缓冲区。
- 打开并将整个文件读取到缓冲区中。
- 弄清楚如何分区每个线程的数据并旋转线程。
- 算法的时间
然后,使用异步读数对其进行修改。请参阅man aio_read
和man 7 aio
以了解需要完成的操作。