`ast.literal_eval` 的最快实现方式

4

我有一些文本(strbytes;实际上是存储在磁盘文件中的gzip格式),可以通过 ast.literal_eval 进行解析。

它由一个字典列表组成,其中字典键为字符串,值为字符串、整数或浮点数。但是也许这个问题可以泛化到任何能够通过 ast.literal_eval 解析的字符串。

它很大:未压缩约为22MB。

最快的解析方法是什么?

当然可以使用 ast.literal_eval,但这似乎非常慢。标准的 eval 稍微快一些(有趣的是,但可能是预期的,这取决于您对Python的了解程度;请参见 ast.literal_eval 的实现),但仍然很慢。

相比之下,当我将同样的数据序列化为JSON,然后加载JSON(json.loads),这会快得多(>10倍)。因此,这表明原则上应该可以像解析JSON一样快速地解析它。

一些统计数据:

Gunzip + read time: 0.15111494064331055
Size: 22035943
compile: 3.1023156170000004
parse: 3.3381092380000004
eval: 3.0252232049999996
ast.literal_eval: 3.765798232
json.loads: 0.2657175249999994

此基准脚本以及生成这种虚假文本文件的脚本可以在此处找到:这里。(也许答案是:"需要更快的C实现;尚未有人实现")。
发帖后,我发现了一些相关问题。不过,我没有通过Google找到它们(也许我的搜索词“更快的literal_eval”不好)。 这部分回答了这个问题的一部分。

2
为什么不将其保存为JSON格式? - user2357112
1
按照写作方式,这篇文章不适合在StackOverflow上发布。 - erip
1
@user2357112supportsMonica 我只是对这个问题很好奇。当然我可以将其保存为JSON,但我还是想知道。而且,我也没有预料到会有这么大的差异。 - Albert
1
请注意,Python 中有更快的 JSON 实现,可以在 https://github.com/ultrajson/ultrajson 上找到。 - user3064538
1
@Albert 很好 - 有些人认为你的问题已经足够明确,我投了一票支持重新开放。对我来说,这是一个具体性问题 - 我并不是在争论你不能测量任何东西,只是边界需要合理清晰。问题似乎仍然可以归结为:如果数据是有效的 JSON,那么最快的 JSON 解析器是什么,而不是 ast.literal_eval,后者操作的是不需要的 JSON 超集。如果你的数据是 JSON 的子集,比如只有整数值,也许你可以利用它。 - ggorlen
显示剩余3条评论
1个回答

1
据我所知,目前不存在比ast.literal_eval更快的实现(嗯,eval本身稍微快一些,但不安全)。
因此,我实现了自己的简单实现,将字面Python代码转换为等效的二进制Pickle数据。 因此,对于一些字节data,您将使用pickle.loads(py_to_pickle(data)),而不是ast.literal_eval(data.decode("utf8")),并且会获得5.5倍的速度提升。
该代码库here是用C++编写的相当直观的实现,并且可以轻松地直接使用ctypes(在代码库中有一个示例)。
新统计数据:
Gunzip + read time: 0.1663219928741455
Size: 22540270
py_to_pickle: 0.539439306
pickle.loads+py_to_pickle: 0.7234611099999999
compile: 3.3440755870000003
parse: 3.6302585899999995
eval: 3.306765757000001
ast.literal_eval: 4.056752016000003
json.loads: 0.3230752619999997
pickle.loads: 0.1351051709999993
marshal.loads: 0.10351717500000035

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