Memory 将[(K,[V])]转换为[(V,[K])]时出现内存故障
我有一个279MB的文件,其中包含约1000万个键/值对,以及约500000个唯一键。它是按键分组的(每个键只需要写入一次),因此给定键的所有值都在一起 我想做的是转置关联,创建一个文件,在该文件中,对按值分组,并将给定值的所有键存储在一起 目前,我正在使用Parsec以元组列表的形式成对读取Memory 将[(K,[V])]转换为[(V,[K])]时出现内存故障,memory,haskell,parsec,Memory,Haskell,Parsec,我有一个279MB的文件,其中包含约1000万个键/值对,以及约500000个唯一键。它是按键分组的(每个键只需要写入一次),因此给定键的所有值都在一起 我想做的是转置关联,创建一个文件,在该文件中,对按值分组,并将给定值的所有键存储在一起 目前,我正在使用Parsec以元组列表的形式成对读取(K[V])(使用惰性IO,以便在Parsec处理输入文件时将其作为流进行处理),其中: 但当我尝试时,我得到了一个错误: memory allocation failed (requested 20971
(K[V])
(使用惰性IO,以便在Parsec处理输入文件时将其作为流进行处理),其中:
但当我尝试时,我得到了一个错误:
memory allocation failed (requested 2097152 bytes)
我可以想到我做错了几件事:
我现在倾向于(1),但我无论如何都不确定。为了允许文件大于可用内存,最好一次处理一小块大小的文件 以下是将文件a复制到新文件B的可靠算法:
- 创建文件B并将其锁定到您的计算机
- 开始循环
- 如果文件中没有下一行,则退出循环
- 读入文件A的下一行
- 对该行应用处理
- 检查文件B是否已包含该行
- 如果文件B不包含该行,则将该行附加到文件B
- 转到循环的开始
- 解锁文件B
我打算在将来重新讨论这个答案并添加代码。数据是否有增加的可能性?如果是的话,我建议不要将while文件读入内存,而是用另一种方式处理数据 一种简单的可能性是使用关系数据库。这将是相当容易的-只需加载您的数据,创建一个适当的索引,并根据需要对其进行排序。数据库将为您完成所有工作。我绝对推荐这个
另一个选择是创建自己的基于文件的机制。例如:
l
n=d`div`l
文件,其中d
是数据总量。(希望这不会超过您的文件描述符限制。您也可以在每次操作后关闭和重新打开文件,但这会使过程非常缓慢。)(k,v)
放入文件编号散列v`mod`l
。这将确保具有相同值v
的对最终位于同一文件中您还可以实现一个基本上可以对任意数量的数据进行排序的方法。发生此错误时,应用程序的内存占用是多少?我认为(1)不是问题所在。是的,它无法尝试分配2MB,但这可能是因为这是一个新的块-即,它已经分配了所有可用内存,而这2MB正是导致整个事情失败的原因。(2)如果您只需要转置的映射,为什么不在读取文件时创建它,而不是在读取文件后创建?如果您可以指定文件格式,我可以尝试一下。您知道,要旋转对象,有两种方法,旋转对象或旋转透视图。。想想看
transpose :: ErrList ParseError (K,[V]) -> Either ParseError [(V,[K])]
transpose = transpose' M.empty
where transpose' _ (Err e) = Left e
transpose' m End = Right $ assocs m
transpose' m (Cons (k,vs) xs) = transpose' (L.foldl' (include k) m vs) xs
include k m v = M.insertWith (const (k:)) v [k] m
memory allocation failed (requested 2097152 bytes)