【发布时间】:2023-03-27 23:12:01
【问题描述】:
我使用attoparsec 为自定义文件编写了一个解析器。
分析报告表明,大约 67% 的内存分配是在一个名为 tab 的函数中完成的,这也是消耗时间最多的。
tab 函数非常简单:
tab :: Parser Char
tab = char '\t'
整个分析报告如下:
ASnapshotParser +RTS -p -h -RTS
total time = 37.88 secs (37882 ticks @ 1000 us, 1 processor)
total alloc = 54,255,105,384 bytes (excludes profiling overheads)
COST CENTRE MODULE %time %alloc
tab Main 83.1 67.7
main Main 6.4 4.2
readTextDevice Data.Text.IO.Internal 5.5 24.0
snapshotParser Main 4.7 4.0
individual inherited
COST CENTRE MODULE no. entries %time %alloc %time %alloc
MAIN MAIN 75 0 0.0 0.0 100.0 100.0
CAF Main 149 0 0.0 0.0 100.0 100.0
tab Main 156 1 0.0 0.0 0.0 0.0
snapshotParser Main 153 1 0.0 0.0 0.0 0.0
main Main 150 1 6.4 4.2 100.0 100.0
doStuff Main 152 1000398 0.3 0.0 88.1 71.8
snapshotParser Main 154 0 4.7 4.0 87.7 71.7
tab Main 157 0 83.1 67.7 83.1 67.7
readTextDevice Data.Text.IO.Internal 151 40145 5.5 24.0 5.5 24.0
CAF Data.Text.Array 142 0 0.0 0.0 0.0 0.0
CAF Data.Text.Internal 140 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Handle.FD 122 0 0.0 0.0 0.0 0.0
CAF GHC.Conc.Signal 103 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding 101 0 0.0 0.0 0.0 0.0
CAF GHC.IO.FD 100 0 0.0 0.0 0.0 0.0
CAF GHC.IO.Encoding.Iconv 89 0 0.0 0.0 0.0 0.0
main Main 155 0 0.0 0.0 0.0 0.0
如何优化?
整个代码for the parser is here.我正在解析的文件大约是77MB。
【问题讨论】:
-
代码中确实有大量对
tab的调用。解析是否经常无法解析文件中的记录?似乎您可能更适合将每一行拆分为Strings 的列表,然后将每个元素解析为其对应的字段。这样所有的选项卡都会被预先解析。您还可以考虑尝试查找现有的 CSV 解析器(可能有一个支持指定分隔符的解析器),它可能更适合此类任务。 -
@bheklilr 据我所知,解析不会失败一次。该文件完全符合解析器定义的格式。我将使用 CSV 库并在此处更新结果。但是还是觉得内存消耗和时间都太高了。
-
我写了很多解析器,但不是在 Haskell 中。你在使用递归下降吗?一般来说,递归下降解析器应该是 IO 绑定的。看看是不是,或者为什么不,我用stackshots,其中很少需要。
-
我想知道
attoparsec解析器的分析结果有多可靠。几乎所有内容都是内联的,并且在启用分析时不会进行许多优化。分析运行所花费的时间是否比不进行分析的执行要长得多? -
@JohnL 是的,你是对的。使用最新版本似乎很重要。但是对于我最初使用的旧版本的 attoparsec,它似乎并没有太大影响。
标签: performance haskell attoparsec