Python 2.6 JSON解码性能

45

我正在使用Python 2.6中的json模块来加载和解码JSON文件,但是目前的性能比预期要慢。我使用的测试案例的大小为6MB,json.loads()需要20秒的时间。

我认为json模块有一些本地代码可以加速解码?

我该如何检查是否正在使用本地代码?

作为对比,我下载并安装了python-cjson模块,并且cjson.decode()在相同的测试案例中只需要1秒钟。

我宁愿使用Python 2.6提供的JSON模块,这样我的代码用户就不需要安装额外的模块。

(我正在Mac OS X上开发,但在Windows XP上也得到类似的结果。)


1
这个问题在Python 2.7中已经解决,根据Tomas,Ivo和TONy.W的比较数据。将其标记为python-2.6。 - smci
根据TONy.W的数据,唯一剩下的问题是在2.7中stdlib json编码仍然比较慢。 - smci
7个回答

31

这个新的Yajl - 另一个JSON库非常快。

yajl        serialize: 0.180  deserialize: 0.182  total: 0.362
simplejson  serialize: 0.840  deserialize: 0.490  total: 1.331
stdlib json serialize: 2.812  deserialize: 8.725  total: 11.537

你可以自行比较这些库

更新: UltraJSON 更快。


1
感谢提供ujson链接 ;) 它让我的gevent/redis搜索服务额外增加了400个请求/秒。 - Justin
我自己尝试了这个测试,并获得了非常有竞争力的结果。根本没有获得20倍的加速。使用比较脚本(来自提供的链接)和大型JSON(20MB)-仍然具有非常可比性的性能。 - Tomas

23

这可能因平台而异,但内置的 json 模块基于 simplejson,不包括 C 速度提升。 我发现 simplejson 与 python-cjson 一样快,因此我更喜欢它,因为它显然具有与内置模块相同的接口。

try:
    import simplejson as json
except ImportError:
    import json

在我看来,这似乎是目前最好的习惯用语,既可以在可用时提供性能,又具备向前兼容性。


顺便说一句,2009年11月11日 http://pypi.python.org/packages/source/s/simplejson/simplejson-2.0.9.tar.gz 在mac 10.4.11 ppc上,gcc 4.2.1 => simplejson/_speedups.c:2256: error: redefinition of ‘PyTypeObject PyEncoderType’ 警告:无法编译C扩展程序,未启用加速。 - denis
1
如果 py-yajilultrajson 更快,那么使用 simplejson 除了与 json 看起来相同且是纯 Python 之外还有什么优点? - Ehtesh Choudhury
@Shurane,无论是py-yajl还是ultrajson都不支持json所支持的所有参数。simplejson由于C加速而更快,并且可以直接替换json - Wilfred Hughes
2
不再是这样了。许多新的 JSON 模块更快。 - noɥʇʎԀʎzɐɹƆ
1
最近有没有调查过这个问题?我的业余时间对3.6中的JSON解码进行了计时,结果表明在处理小文件时,JSON比simplejson或ujson(后者似乎已经不再维护)更快。 - pbaylis

17

我对同一个文件进行了10次解析,文件大小为1,856,944字节。

Python 2.6:

yajl        serialize: 0.294  deserialize: 0.334  total: 0.627
cjson       serialize: 0.494  deserialize: 0.276  total: 0.769
simplejson  serialize: 0.554  deserialize: 0.268  total: 0.823
stdlib json serialize: 3.917  deserialize: 17.508 total: 21.425

Python 2.7:

yajl        serialize: 0.289  deserialize: 0.312  total: 0.601
cjson       serialize: 0.232  deserialize: 0.254  total: 0.486
simplejson  serialize: 0.288  deserialize: 0.253  total: 0.540
stdlib json serialize: 0.273  deserialize: 0.256  total: 0.528

不确定为什么你的结果中数字不成比例。我猜是因为使用了更新的库?


1
我还注意到Python 2.6和2.7之间的stdlib(即内置)json存在显着的性能差异。这就是为什么Python 2.7比2.6更受欢迎的另一个原因。 - RayLuo
4
原因很简单:在Python 2.7中添加了对JSON的C加速。根据发布说明:“已更新模块:JSON模块升级至simplejson包的2.0.9版本,其中包含一个C扩展,可使编码和解码更快。” http://docs.python.org/dev/whatsnew/2.7.html - Ferdinand Beyer
3
非常有价值的数字,Tomas。因此2.7解决了所有问题。 - smci

15

请看 UltraJSON:https://github.com/esnme/ultrajson

这是我的测试(代码来自: https://gist.github.com/lightcatcher/1136415

平台:OS X 10.8.3 MBP 2.2 GHz 英特尔 Core i7

JSON 库:

simplejson==3.1.0

python-cjson==1.0.5

jsonlib==1.6.1

ujson==1.30

yajl==0.3.5

JSON Benchmark
2.7.2 (default, Oct 11 2012, 20:14:37)
[GCC 4.2.1 Compatible Apple Clang 4.0 (tags/Apple/clang-418.0.60)]
-----------------------------
ENCODING
simplejson: 0.293394s
cjson: 0.461517s
ujson: 0.222278s
jsonlib: 0.428641s
json: 0.759091s
yajl: 0.388836s

DECODING
simplejson: 0.556367s
cjson: 0.42649s
ujson: 0.212396s
jsonlib: 0.265861s
json: 0.365553s
yajl: 0.361718s

1
截至2014年8月,这些结果在最新的库版本上基本准确。我们针对一些随机数据进行了测试,发现ujson略微(约5-10%)优于cjson,而cjson大约是simplejson的两倍和json的三倍。cjson的性能在特定数据集上也相当不稳定,因此我们坚持使用ujson。 - Eric Chen

3

对于那些使用requests包解析请求输出的人,例如:

res = requests.request(...)

text = json.loads(res.text)

这对于较大的响应内容可能非常缓慢,在我的2017款MacBook上,6 MB的响应内容需要约45秒。这不是由于json解析器慢造成的,而是由于res.text调用缓慢的字符集确定引起的。
您可以通过在调用res.text之前设置字符集,并使用cchardet包(也可参见此处)来解决此问题。
if res.encoding is None:
    res.encoding = cchardet.detect(res.content)['encoding']

这使得响应文本的json解析几乎瞬间完成!

2
在我的Windows上安装的Python 2.6.1中,json包加载了内置于运行时的_json模块。 json加速模块的C源代码在这里。请注意保留HTML标签。
>>> import _json
>>> _json
<module '_json' (built-in)>
>>> print _json.__doc__
json speedups
>>> dir(_json)
['__doc__', '__name__', '__package__', 'encode_basestring_ascii', 'scanstring']
>>> 

我也认为带有_json的json会很快。但基准测试证明了我的错误。 - Ivo Danihelka
1
json 包在底层已经使用了 _json C 模块。直接访问它的用处很小。 - Martijn Pieters

1
尽管_json可用,但我注意到在CPython 2.6.6上JSON解码非常缓慢。虽然我没有与其他实现进行比较,但在性能关键循环内部时,我已经切换到字符串操作。

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