为什么json.load比ast.literal_eval快一个数量级?

时间:2014-01-19 22:16:33

标签: python json parsing benchmarking

在回答关于how to parse a text file containing arrays of floats的问题后,我运行了以下基准:

import timeit
import random

line = [random.random() for x in range(1000)]
n = 10000

json_setup = 'line = "{}"; import json'.format(line)
json_work = 'json.loads(line)'
json_time = timeit.timeit(json_work, json_setup, number=n)
print "json: ", json_time

ast_setup = 'line = "{}"; import ast'.format(line)
ast_work = 'ast.literal_eval(line)'
ast_time = timeit.timeit(ast_work, ast_setup, number=n)
print "ast: ", ast_time

print "time ratio ast/json: ", ast_time / json_time

我多次运行此代码并始终得到这样的结果:

$ python json-ast-bench.py 
json: 4.3199338913
ast: 28.4827561378
time ratio ast/json:  6.59333148483

因此,对于此用例,json似乎比ast快一个数量级。

我在Python 2.7.5+和Python 3.3.2 +上都有相同的结果。

问题:

  1. 为什么json.loads这么快? This question似乎意味着ast在输入数据(双引号或单引号)方面更灵活。
  2. 是否存在使用ast.literal_eval优于json.loads的用例,尽管速度较慢?
  3. 编辑:无论如何,如果性能很重要,我建议使用UltraJSON(正如我在工作中使用的那样,使用相同的迷你基准测试比json快4倍)。

1 个答案:

答案 0 :(得分:9)

这两个函数正在解析完全不同的语言-JSON和Python文字语法。*正如literal_eval所说:

  

提供的字符串或节点可能只包含以下Python文字结构:字符串,字节,数字,元组,列表,字符串,集合,布尔值和None

相比之下,

JSON只处理双引号JavaScript字符串文字(与Python' s **不完全相同),JavaScript编号(仅限int和float ***),对象(大致相当)对于dicts),数组(大致相当于列表),JavaScript布尔值(与Python不同)和null

这两种语言碰巧有一些重叠的事实并不意味着它们是同一种语言。


  

为什么json.loads这么快?

因为Python文字语法是一种比JSON更复杂和更强大的语言,所以它的解析速度可能会慢一些。并且,可能更重要的是,因为Python文字语法不打算用作数据交换格式(事实上,它特别是而不是应该用于此),没有人可能努力使其快速进行数据交换。****

  

这个问题似乎意味着ast在输入数据(双引号或单引号)方面更灵活

那,和原始字符串文字,Unicode与字节字符串文字,复数,集合,以及JSON无法处理的各种其他事情。

  

是否存在使用ast.literal_eval而不是json.loads的用例,虽然速度较慢?

是。如果要解析Python文字,则应使用ast.literal_eval。 (或者,更好的是,重新考虑你的设计,这样你就不想解析Python文字...)


*这是一个模糊的术语。例如,-2不是Python中的literal,而是运算符表达式,但literal_eval可以处理它。当然,元组/列表/字典/集合显示不是文字,但literal_eval可以处理它们 - 除了还显示了理解,literal_eval无法处理它们。 ast模块中的其他功能可以帮助您找出真正的内容,而不是文字内容,例如ast.dump(ast.parse("expr"))

**例如,"\q"是JSON中的错误。

***从技术上讲,JSON只处理一个"数字" type,浮点数。但Python的json模块解析没有小数点或指数为整数的数字,在许多其他语言中也是如此。' JSON模块。

****如果你错过了蒂姆·彼得斯对这个问题的评论:" ast.literal_eval被如此轻易地使用,没有人觉得值得花时间工作(& work,& amp; ;工作)加速它。相比之下,JSON库通常用于解析千兆字节的数据。"