解析大文件时,为什么Scala的组合子解析速度慢?我能做什么?

时间:2014-04-16 18:41:00

标签: regex performance scala parsing parser-combinators

我需要解析拥有数百万行的文件。我注意到我的组合器解析器变得越来越慢,因为它解析了越来越多的行。问题似乎出现在scala" rep"或正则表达式解析器,因为即使对于下面显示的简单示例解析器,也会发生此行为:

def file: Parser[Int] = rep(line) ^^ { 1 }  // a file is a repetition of lines

def line: Parser[Int] = """(?m)^.*$""".r ^^ { 0 } // reads a line and returns 0

当我尝试使用这个简单的解析器解析具有数百万行相等长度的文件时,它在开始时解析46行/ ms。在370000行之后,速度降至20行/ ms。在840000行之后,它下降到10行/ ms。经过1790000行,5行/ ms ......

我的问题是:

  • 为什么会这样?

  • 我该怎么做才能防止这种情况发生?

1 个答案:

答案 0 :(得分:2)

这可能是由于Java 7u6中没有子串作为原始字符串的一部分而发生的变化。这么大的字符串会一遍又一遍地被复制,导致大量的内存流失(以及其他事情)。随着你增加你解析的东西的数量(我假设你至少存储了一些东西),垃圾收集器有越来越多的工作要做,所以创建所有额外的垃圾会有更陡峭和更陡的惩罚

有一个ticket to fix the memory usage,来自Zach Moazeni的代码可以让你将你的字符串包装在一个构造中,该构造将正确地创建子字符串(你可以将它传递给解析器来代替字符串)。

这不一定会改变解析最终减慢的总体结果,但它应该有助于减少总体时间。

另外,我不建议将文件重复为一行。您正在使解析器在不需要时跟踪整个文件。我一次喂它一行。 (如果线条很短,你可能不需要上面的修复。)