向后读取文件的适当的madvise设置是什么?

时间:2013-01-19 10:20:59

标签: c++ c++11 mmap

我在64位Linux机器上使用gcc 4.7.2。

我有20个大的排序二进制POD文件,我需要在外部合并排序中作为最终合并的一部分阅读。

通常,在mmap写入磁盘之前,我会multiset<T,LessThan>所有要读取的文件并使用mmap来管理从小到大的合并排序。

但是,我意识到,如果我在每个文件上保留std::mutex,我可以创建第二个线程,向后读取文件,同时从大到小排序。如果我事先决定第一个线程将采用正好n / 2个元素而第二个线程将采用其余的元素,那么我将不需要在输出端使用互斥锁。

在这种特殊情况下,读取锁定争用,平均可能会发生在20中,因此这是可以接受的。

现在,这是我的问题。在第一种情况下,很明显我应该使用madvise调用MADV_SEQUENTIAL,但我不知道我应该为第二种情况做什么,我正在向后读取文件。

我在手册页中看不到MADV_REVERSE。我应该使用MADV_NORMAL还是根本不打电话给madvise

回想一下,当数据量太大而无法放入内存时,需要进行外部排序。因此,我们留下了一个更复杂的算法,将磁盘用作临时存储。划分和征服算法通常涉及分解数据,进行部分排序,然后合并部分排序。

我的外部合并排序步骤

  1. 取n = 10亿个随机数并将它们分成20个相同大小的碎片。
  2. 将每个分片从小到大分别排序,并将每个分片写入自己的文件中。
  3. 打开40个mmap,每个文件2个,一个用于前进,一个用于向后移动,将互斥锁与每个文件相关联。
  4. 为转发线程实例化std::multiset<T,LessThan> buff_fwd;,为反向线程实例化std::multiset<T,GreaterThan> buff_rev。有些人喜欢在这里使用优先级队列,但实质上,插入插件容器在这里可以使用。
  5. 我喜欢调用两个缓冲区surface和rockbottom,表示尚未添加到最终排序中的最小和最大数字。
  6. 从分片中添加项目,直到n / 2用完为止,并使用mmap从一开始向中间,从另一个线程的结尾向中间将分片刷新到一个输出文件。您基本上可以随意刷新,但至少有一个应该在缓冲区占用太多内存之前执行此操作。

1 个答案:

答案 0 :(得分:1)

我建议:

MADV_RANDOM

防止无用的预读(方向错误)。