用Python编写快速解析器

11 投票
2 回答
19415 浏览
提问于 2025-04-15 22:05

我写了一个用纯Python做的递归解析器,专门用来处理我们在一节课上用到的一种文件格式(ARFF)。现在运行我的作业提交时速度非常慢。经过调查发现,最耗时的就是我的解析器。它消耗了大量的CPU时间,而硬盘并不是瓶颈。

我想知道在Python中有没有更高效的写解析器的方法?我不想把它重写成C语言。我尝试过使用jython,但性能下降得很厉害!我解析的文件有的非常大(超过150MB),而且行也很长。

我现在的解析器只需要看一个字符的前瞻。我本来想在这里贴出源代码,但我不知道这样是否合适。毕竟提交的截止日期还没有到。不过,这次作业的重点并不是解析器。你可以选择任何你想用的语言,而且Java已经有一个解析器了。

注意:我使用的是x86_64系统,所以psyco(看起来PyPy也不行)都不适用。

更新:我现在把我的解析器/写入器上传到了bitbucket

2 个回答

10

我给出的最基本建议是,尽量一次性把整个文件或者至少大部分内容读入内存。你不想一个字符一个字符地去读,也不想到处寻找。无论后台是怎么处理的,把整个文件放在内存里会更方便,这样你可以随意操作。

我在Python中写过解析器,实际上它们并不比其他语言写的解析器慢。很多时候,问题出在你做了不必要的工作。比如,创建、销毁再重新创建同一个对象,这样的操作比把它存起来要耗费更多资源。反复计算同一个值也比存起来要麻烦得多,等等。

在Python中,一个常见的误区是做了很多不必要的字符串操作。不要一个字符一个字符地拼接字符串;在构建你的“标记”时,应该在“主”字符串上进行操作,然后一次性提取出标记。(换句话说,先找到“主”字符串的开始和结束位置,然后用token = master[start:end]来获取它。)一个字符一个字符地拼接字符串会让你的程序变得很慢。如果你真的需要用for c in master: newstr += c这种方式,可能更好的办法是先把字符放到一个列表里,然后用newstr = ''.join(newstr_charlist)来合并它们。

10

你可以使用ANTLR或者pyparsing,它们可能会让你的解析过程更快。

如果你想保留现在的代码,可以考虑Cython或者PyPy,它们能提高你的程序性能(有时候能提升到4倍)。

撰写回答