【发布时间】:2013-02-15 14:59:05
【问题描述】:
这个问题在 StackOverflow 上经常出现,但是我已经阅读了之前所有的相关答案,并且对这个问题有一点曲解。
我有一个 23Gb 的文件,其中包含 4.75 亿行大小相等的行,每行包含一个 40 个字符的哈希码,后跟一个标识符(一个整数)。
我有一个传入的哈希码流 - 总共有数十亿个 - 对于每个传入的哈希码,我需要找到它并打印出相应的标识符。这项工作虽然很大,但只需要完成一次。
文件太大,我无法读入内存,所以我一直在尝试通过以下方式使用 mmap:
codes = (char *) mmap(0,statbuf.st_size,PROT_READ,MAP_SHARED,codefile,0);
然后我只是根据代码中的地址使用地址算法进行二进制搜索。
这似乎开始工作很漂亮,并在几秒钟内产生了几百万个标识符,使用了 100% 的 cpu,但在经过一些看似随机的时间后,它会减慢到爬行。当我使用 ps 查看进程时,它已从使用 100% 的 cpu 的状态“R”变为使用 1% 的 cpu 的状态“D”(磁盘绑定)。
这是不可重复的 - 我可以在相同的数据上再次启动该过程,并且它可能会运行 5 秒或 10 秒,然后才会发生“爬行缓慢”。昨晚有一次,在这件事发生之前我有将近一分钟的时间。
一切都是只读的,我没有尝试对文件进行任何写入,并且我已经停止了机器上的所有其他进程(我控制的)。它是现代 Red Hat Enterprise Linux 64 位机器。
有谁知道这个进程为什么会被磁盘绑定以及如何停止它?
更新:
感谢大家的回答和您的想法;我以前没有尝试过所有各种改进,因为我想知道我是否以某种方式错误地使用了 mmap。但答案的要点似乎是,除非我能将所有内容都挤进内存,否则我将不可避免地遇到问题。所以我将散列码的大小压缩到不产生任何重复的前导前缀的大小——前 15 个字符就足够了。然后我将生成的文件拉入内存,并以大约 20 亿个批次运行传入的哈希码。
【问题讨论】:
-
您遇到了虚拟内存的限制。虽然活动数据集适合内存,但一切都是正常的;当您需要对太大而无法放入内存的数据集进行随机访问时,您开始进行硬分页,成为磁盘绑定。没有一个简单的方法可以解决这个问题。整数是存储为 4 字节或 8 字节二进制值还是字符串?是否有可能重组 23 GiB 文件?
-
@paxdiablo:问题不在于虚拟内存大小的限制;问题是底层物理内存。该程序仍在运行,但是当物理内存为 16 GiB 时,随机访问超过 23 GiB 的数据,这意味着一旦你在内存中获得了 2/3 的文件,此后,平均而言,你必须三分之二读取一个内存访问的新页面,这非常慢。
-
@JonathanLeffler:是的,我在重读后意识到你的意思(因此我删除了评论)。什么让我断言这是虚拟内存的限制(我将其读为大小)而不是虚拟内存管理(即映射,正如您在回复中解释的那样)。跨度>
-
你有多少内存?具体来说,您一次可以在内存中保存多少个传入哈希码(并排序)?您能否反转问题,按顺序读取文件并将其与传入数据进行匹配,而不是反之亦然?
标签: c linux binary-search