泡菜还是json?


114

我需要将一个dict密钥为type str且值为ints 的小对象保存到磁盘,然后将其恢复。像这样:

{'juanjo': 2, 'pedro':99, 'other': 333}

最佳选择是什么,为什么?使用pickle或使用序列化它simplejson

我正在使用Python 2.6。


转换成什么?另外,从什么意义上说更好
SilentGhost 2010年

10
在2.6中,您不会使用simplejson,而会使用内置json模块(具有相同的确切接口)。
Mike Graham 2010年

5
“最好”?最适合什么?速度?复杂?灵活性?成本?
S.Lott 2010年


Answers:


68

如果您没有任何互操作性要求(例如,您将仅使用Python使用数据)并且二进制格式很好,请使用cPickle,它将为您提供真正快速的Python对象序列化。

如果您希望互操作性或想要一种文本格式来存储数据,请使用JSON(或其他一些适当的格式,具体取决于您的约束)。


48
JSON 似乎比cPickle
2012年

5
我的回答强调了我认为在选择任何一种解决方案时最重要的考虑因素。我没有声称任何一个都比另一个要快。如果JSON更快并且适合使用JSON,请使用JSON!(即没有理由拒绝您投票。)
HåvardS 2012年

10
我的观点是:没有真正的理由根据您的前提在JSON上使用cPickle(或pickle)。当我第一次阅读您的答案时,我认为原因可能是速度,但是由于事实并非如此... :)
mac

14
@mac引用的基准仅测试字符串。我分别测试了str,int和float,发现使用float序列化时json比cPickle慢,但是使用float非序列化时json更快。对于int(和str),json双向都更快。数据和代码:gist.github.com/marians/f1314446b8bf4d34e782
Marian

24
现在,cPickle的最新协议比JSON更快。关于JSON速度更快的最高评价已经过时了几年。 stackoverflow.com/a/39607169/1007353
JDiMatteo

104

对于序列化,我更喜欢JSON而不是pickle。取消选择可以运行任意代码,并且pickle用于在程序之间传输数据或在会话之间存储数据是一个安全漏洞。JSON不会引入安全漏洞,并且已标准化,因此,您可以根据需要使用不同语言的程序访问数据。


谢谢。无论如何,我将在同一程序中转储和加载。
Juanjo Conti 2010年

2
尽管当前应用程序中的安全风险可能较低,但是JSON允许您完全关闭整个过程。
Mike Graham 2010年

4
可以创建一种腌制病毒,将其自身腌制到装入后腌制的所有东西中。使用json这是不可能的。
用户

2
除了安全性,JSON还具有其他优点,它使迁移变得容易,因此您可以加载由较早版本的应用程序保存的数据。同时,您可以添加一个字段,或替换整个子结构。为dict / list编写这样的转换器(迁移)是很直接的,但是使用Pickle,首先很难加载它,甚至还没有想到要进行转换。
vog

2
我没有考虑过这方面(安全性和腌制对象运行任意代码的能力)。感谢您指出了这一点!
CaffeinatedMike


20

如果您主要关注速度和空间,请使用cPickle,因为cPickle比JSON快。

如果您更关注互操作性,安全性和/或人类可读性,请使用JSON。


其他答案中引用的测试结果记录在2010年,2016年使用cPickle 协议2更新的测试显示:

  • cPickle 3.8倍更快的加载速度
  • cPickle 1.5倍读取速度更快
  • cPickle编码稍小

使用这个gist可以自己重现这一点,它基于康斯坦丁在其他答案中引用的基准,但是使用协议2而不是pickle的cPickle,并且使用pickle的json(因为json比simplejson快)来使用json ,例如

wget https://gist.github.com/jdimatteo/af317ef24ccf1b3fa91f4399902bb534/raw/03e8dbab11b5605bc572bc117c8ac34cfa959a70/pickle_vs_json.py
python pickle_vs_json.py

在不错的2015 Xeon处理器上使用python 2.7的结果:

Dir Entries Method  Time    Length

dump    10  JSON    0.017   1484510
load    10  JSON    0.375   -
dump    10  Pickle  0.011   1428790
load    10  Pickle  0.098   -
dump    20  JSON    0.036   2969020
load    20  JSON    1.498   -
dump    20  Pickle  0.022   2857580
load    20  Pickle  0.394   -
dump    50  JSON    0.079   7422550
load    50  JSON    9.485   -
dump    50  Pickle  0.055   7143950
load    50  Pickle  2.518   -
dump    100 JSON    0.165   14845100
load    100 JSON    37.730  -
dump    100 Pickle  0.107   14287900
load    100 Pickle  9.907   -

带有pickle协议3的Python 3.4甚至更快。


11

JSON还是泡菜?JSON 泡菜怎么样!您可以使用jsonpickle。它易于使用,并且磁盘上的文件是JSON,因此可读。

http://jsonpickle.github.com/


2
有没有人将其性能作为选择基准的基准?在性能上是否可以与benfrederickson.com/dont-pickle-your-data所示的原始json 相提并论
Josep Valls

这不是一个广泛的基准,但是我有一个现有的游戏,该游戏使用pickle(python3)来保存关卡。我想尝试jsonpickle来实现人类可读的方面-但是可悲的是,保存级别慢得多。jsonpickle需要1597毫秒,关卡时需要88毫秒或常规泡菜。对于水平负载,jsonpickle为1604ms,pickle为388。我喜欢人类可读的保存的可惜。
尼尔·麦吉尔

我在我们的交易系统中对此进行了测试,与pickle相比,其可读性约为序列化+反序列化速度损失的2倍。伟大的,但是。
nurettin

6

我尝试了几种方法,发现使用cPickle并将dumps方法的协议参数设置为:cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)是最快的转储方法。

import msgpack
import json
import pickle
import timeit
import cPickle
import numpy as np

num_tests = 10

obj = np.random.normal(0.5, 1, [240, 320, 3])

command = 'pickle.dumps(obj)'
setup = 'from __main__ import pickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("pickle:  %f seconds" % result)

command = 'cPickle.dumps(obj)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle:   %f seconds" % result)


command = 'cPickle.dumps(obj, protocol=cPickle.HIGHEST_PROTOCOL)'
setup = 'from __main__ import cPickle, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("cPickle highest:   %f seconds" % result)

command = 'json.dumps(obj.tolist())'
setup = 'from __main__ import json, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("json:   %f seconds" % result)


command = 'msgpack.packb(obj.tolist())'
setup = 'from __main__ import msgpack, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("msgpack:   %f seconds" % result)

输出:

pickle         :   0.847938 seconds
cPickle        :   0.810384 seconds
cPickle highest:   0.004283 seconds
json           :   1.769215 seconds
msgpack        :   0.270886 seconds

4

就个人而言,我通常更喜欢JSON,因为数据是人类可读的。当然,如果您需要序列化JSON不会接受的内容,则可以使用pickle。

但是对于大多数数据存储而言,您不需要序列化任何奇怪的东西,而JSON则容易得多,并且始终允许您在文本编辑器中将其弹出并自行检查数据。

速度不错,但是对于大多数数据集而言,差异可以忽略不计;无论如何,Python通常并不太快。



1
真正。但是对于100列表中的元素,人眼可以忽略不计。使用较大的数据集时绝对不同。
rickcnagy 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.