Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ajax/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Memory 将[(K,[V])]转换为[(V,[K])]时出现内存故障_Memory_Haskell_Parsec - Fatal编程技术网

Memory 将[(K,[V])]转换为[(V,[K])]时出现内存故障

Memory 将[(K,[V])]转换为[(V,[K])]时出现内存故障,memory,haskell,parsec,Memory,Haskell,Parsec,我有一个279MB的文件,其中包含约1000万个键/值对,以及约500000个唯一键。它是按键分组的(每个键只需要写入一次),因此给定键的所有值都在一起 我想做的是转置关联,创建一个文件,在该文件中,对按值分组,并将给定值的所有键存储在一起 目前,我正在使用Parsec以元组列表的形式成对读取(K[V])(使用惰性IO,以便在Parsec处理输入文件时将其作为流进行处理),其中: 但当我尝试时,我得到了一个错误: memory allocation failed (requested 20971

我有一个279MB的文件,其中包含约1000万个键/值对,以及约500000个唯一键。它是按键分组的(每个键只需要写入一次),因此给定键的所有值都在一起

我想做的是转置关联,创建一个文件,在该文件中,对按值分组,并将给定值的所有键存储在一起

目前,我正在使用Parsec以元组列表的形式成对读取
(K[V])
(使用惰性IO,以便在Parsec处理输入文件时将其作为流进行处理),其中:

但当我尝试时,我得到了一个错误:

memory allocation failed (requested 2097152 bytes)
我可以想到我做错了几件事:

  • 2MB似乎有点低(比我的机器安装的2GB内存要小得多),所以我可能需要告诉GHC可以使用更多
  • 我的问题可能与算法/数据结构有关。也许我用错工具了
  • 我尝试使用懒惰IO可能会回来咬我

  • 我现在倾向于(1),但我无论如何都不确定。

    为了允许文件大于可用内存,最好一次处理一小块大小的文件

    以下是将文件a复制到新文件B的可靠算法:

    • 创建文件B并将其锁定到您的计算机
    • 开始循环
      • 如果文件中没有下一行,则退出循环
      • 读入文件A的下一行
      • 对该行应用处理
      • 检查文件B是否已包含该行
      • 如果文件B不包含该行,则将该行附加到文件B
      • 转到循环的开始
    • 解锁文件B
    将文件a的副本复制到临时文件夹中并在您使用它时将其锁定也是值得的,这样网络上的其他人就不会被阻止更改原始文件,但您可以获得文件的快照,因为它在过程开始时就是这样的


    我打算在将来重新讨论这个答案并添加代码。

    数据是否有增加的可能性?如果是的话,我建议不要将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)