【问题标题】:parsec running out of memory秒差距内存不足
【发布时间】:2015-06-14 03:25:59
【问题描述】:

我为一个大型 csv 文件编写了一个解析器,该文件适用于较小的子集,但内存不足约 1.5m 行(实际文件)。 在最初将所有元素解析为列表后(使用 manyTill),我改为使用解析器状态将它们存储在单个二叉搜索树中 - 这适用于大文件。

我已经将“元素类型”拆分为三种不同的类型,并希望将它们存储在自己的树中,从而产生三种不同类型的树。 但是,此版本仅适用于较小的测试文件,而较大的测试文件内存不足。

import qualified Data.Tree.AVL as AVL
import qualified Text.ParserCombinators.Parsec as Parsec
----
data ENW = ENW (AVL.AVL Extent) (AVL.AVL Node) (AVL.AVL Way)
---- used to be Element = Extent | Node | Way  in a (Tree Element) - this worked
csvParser :: Parsec String ENW ENW
csvParser = do (Parsec.manyTill (parseL) Parsec.eof) >> Parsec.getState
    where parseL = parseLine >> ((Parsec.newline >> return ()) <|> Parsec.eof)

parseLine :: Parsec String ENW ()
parseLine = parseNode <|> parseWay <|> parseExtents

parseNode :: Parsec String ENW ()
parseNode = Parsec.string "node" *> (flip addNode <$> (Node <$> identifier <*> float <*> float)) >>= Parsec.updateState
    where identifier = Parsec.tab *> (read <$> Parsec.many1 Parsec.digit)
          float      = Parsec.tab *> (read <$> parseFloat)

addNode :: ENW -> Node -> ENW
addNode (ENW e n w) node  = (ENW e (AVL.push (sndCC node) node n) w)

parseWay 和 parseExtent 遵循相同的模式,整个事情都是从

开始的
Parsec.runParser csvParser (ENW AVL.empty AVL.empty AVL.empty) "" input

我不明白使用三棵小树而不是一棵大树会导致内存问题。

【问题讨论】:

  • 只是在黑暗中刺伤 - Parsec 数据类型在“用户状态”参数中是严格的,这是您存储数据的位置。当您直接以该用户状态存储树时,在解析时会对其进行严格评估。现在您已经对数据进行了装箱 - 您拥有三​​棵树是无关紧要的,只是将树放入数据类型中 - 这些树将被延迟评估,这可能会导致各种内存泄漏。尝试使您的数据类型的字段严格。

标签: haskell out-of-memory parsec


【解决方案1】:

您是否有充分的理由不使用Cassava?它可用于流式传输 CSV 数据,并且可能比临时 CSV 解析器更强大。我自己的经验表明它具有出色的性能,并且可以轻松扩展以解析您自己的类型。

编辑:看起来您正在使用制表符分隔的值数据,而不是逗号分隔的数据,但 Cassava 允许您指定分隔列的分隔符。看起来您拥有的数据可能在每一行上都不同因此您可能需要使用 Cassava 的“原始”格式,它为每一行返回一个 Vector ByteString,然后您可以根据第一个元素对其进行解析。

我以前从未见过有人使用过 AVL 树包,您是否有充分的理由不使用更标准的结构?那个包已经很老了(最后一次更新是在 2008 年),更新的包可能会表现得更好。

【讨论】:

  • 我只是想学习一些东西,而 parsec 似乎值得。是的,它是 \t 和 \n 分隔值,但我不知道 'tsv' 是否是一个东西。我最初使用我自己的树类型,但我想在抱怨之前先试试别人的。我需要对元素进行排序并且不知道确切的数字,所以在列表(由 manyTill 返回)立即爆炸后,我首先想到的是一棵树。
  • PS:avl包纯属巧合。我知道这项工作可能有比 parsec 更好的库,但我想研究一下 parsec 以了解最基本的工具(第一次在这里使用它)。另一件事是,这似乎与解析本身无关,从长远来看,躲避问题对我没有帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-10-15
  • 2011-05-21
  • 1970-01-01
  • 2021-12-20
  • 2021-10-29
  • 1970-01-01
相关资源
最近更新 更多