ANTLR4生成的Python解析器运行缓慢,但在Java中运行速度很快。

9

我想将ANTLR3语法转换为ANTLR4语法,以便与antlr4-python2-runtime一起使用。这个语法是一个C/C++模糊解析器。

在转换它之后(基本上是删除树操作符和语义/句法谓词),我使用以下命令生成了Python2文件:

java -jar antlr4.5-complete.jar -Dlanguage=Python2 CPPGrammar.g4

代码生成没有任何错误,所以我将其导入到我的Python项目中(我正在使用PyCharm)进行一些测试:

import sys, time
from antlr4 import *
from parser.CPPGrammarLexer import CPPGrammarLexer
from parser.CPPGrammarParser import CPPGrammarParser

currenttimemillis = lambda: int(round(time.time() * 1000))

def is_string(object):
    return isinstance(object,str)

def parsecommandstringline(argv):
    if(2!=len(argv)):
        raise IndexError("Invalid args size.")
    if(is_string(argv[1])):
        return True
    else:
        raise TypeError("Argument must be str type.")

def doparsing(argv):
    if parsecommandstringline(argv):
        print("Arguments: OK - {0}".format(argv[1]))
        input = FileStream(argv[1])
        lexer = CPPGrammarLexer(input)
        stream = CommonTokenStream(lexer)
        parser = CPPGrammarParser(stream)
        print("*** Parser: START ***")
        start = currenttimemillis()
        tree = parser.code()
        print("*** Parser: END *** - {0} ms.".format(currenttimemillis()-start))
        pass

def main(argv):
    tree = doparsing(argv)
    pass

if __name__ == '__main__':
    main(sys.argv)

问题在于解析速度非常慢。对于包含约200行的文件,需要超过5分钟才能完成解析,而在antlrworks中解析相同文件仅需1-2秒钟。 分析antlrworks树,我注意到expr规则及其所有子代被频繁调用,因此我认为需要简化/更改这些规则以使解析器运行更快: expr_tree 我的假设是否正确,或者在转换语法时是否犯了一些错误?有什么方法可以使解析速度与antlrworks一样快吗?
更新: 我将相同的语法导出到Java中,只需要795毫秒就能完成解析。问题似乎更多地与Python实现有关,而不是与语法本身有关。有什么方法可以加快Python解析速度吗? 我在这里读到python可能比java慢20-30倍,但在我的情况下,python慢了约400倍!

必须对规则执行时间进行分析,才能确保其准确性。可能是由于解析器中使用了大量的否定集合、文字等,或者其他看似无害的因素导致的。 - GRosenberg
@GRosenberg 谢谢您的评论。我不是ANTLR专家,但是在解析器中,我的语法和原始语法似乎没有很多否定集或文字。我认为这是与 antlr4-python2-runtime 相关的错误,因为在Java上解析相同的文件只需要1秒钟。Python可能会慢一些,但是慢400倍太多了,我认为这不是我的问题。 - Vektor88
尽管如此,识别运行时性能不佳的方面的最佳方法仍然是对个别规则进行分析,并确定处理速度较慢的特定规则方面。问题只存在于你的一侧,也就是说,你的语法在某种程度上触发了减速。几乎可以肯定,需要对运行时进行更改。难点在于找出需要修复的地方。幸运的是,关键点就在你的语法中。尽力将问题隔离并在Antlr Github存储库上创建一个问题。这是最快解决问题的方式。 - GRosenberg
4个回答

10

我确认Python 2和Python 3运行时存在性能问题。经过一些修补,我使Python 3运行时的速度提升了10倍(从大约5秒降至约400毫秒)。 https://github.com/antlr/antlr4/pull/1010


2
拉取请求已被接受:使用最新的antlr4 Python运行时或等待在pypi上发布的4.5.3版本。 - Pinaraf
请回答我的问题(因为我正在赠送50个悬赏积分)。https://stackoverflow.com/questions/53653323/what-are-the-ways-to-speed-up-parsing-in-antlr4 - vineeshvs

4

我曾遇到类似的问题,所以决定以可能的解决方案来提高这篇旧帖子的排名。在使用TestRig时,我的语法分析速度非常快,但在Python3上却异常缓慢。

在我这种情况下,问题出在我使用的非贪婪标记来生成单行注释(在C/C++中是双斜杠,“%”在我这里):

TKCOMM : '%' ~[\r\n]* -> skip ;

这个帖子从sharwell在这个讨论中的发言得到了一些支持:

当性能是一个问题时,尤其是在解析器规则中,应避免使用非贪婪操作符。

为了测试这种情况,您可能想要从语法中删除非贪婪规则/标记。


你用了什么来实现更好的注释规则? - DainDwarf
@DainDwarf 目前我正在使用不带ANTLR的单独程序进行预处理和删除注释。在此之前,我将其用作解决方法,直到此线程引用的性能补丁到达pip。 - Caian

3

我在这里发布,因为这可能对发现这个主题的人有用。

自发布以来,Antlr的Python目标已经进行了多次性能改进。尽管如此,Python解释器本质上比Java或其他编译语言慢。

我为Antlr的Python3目标编写了一个Python加速器代码生成器。它使用Antlr C++目标作为Python扩展。词法分析和解析完全在C++中完成,然后使用自动生成的访问者在Python中重新构建结果解析树。初步测试显示取决于语法和输入,速度提升了5倍至25倍,而且我还有一些改进的想法。

这是代码生成工具:https://github.com/amykyta3/speedy-antlr-tool

这是一个完全功能的示例:https://github.com/amykyta3/speedy-antlr-example

希望这对那些喜欢在Python中使用Antlr的人有用!


我很久以前就给这篇文章点赞了,但直到今天才抽出时间来运行它。我将我的希望寄托在这个工具上,现在它回报了我巨大的收益!多亏了你的工具,我现在可以将8000个解析文件的时间从7分钟缩短到3分钟。我要看看我能否进一步推动它的极限。我发现了一些错误,希望很快能发布拉取请求。干杯! - Andrej Mohar
谢谢!很高兴听到它对你有用! - Alex Mykyta

0
这些天我在使用Python3目标中的ANTLR。 一个有500多行的文件只需要不到20秒就可以解析完毕。 所以转向Python3目标可能会有所帮助。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接