【问题标题】:Pickle or json?泡菜还是json?
【发布时间】:2011-01-16 14:04:45
【问题描述】:

我需要将一个小dict 对象保存到磁盘,它的键是str 类型,值是ints 然后恢复它。像这样的:

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

什么是最好的选择,为什么?使用picklesimplejson 对其进行序列化?

我使用的是 Python 2.6。

【问题讨论】:

  • 把它转换成什么?另外,在什么意义上更好
  • 在 2.6 中你不会使用simplejson,你会使用内置的json 模块(具有完全相同的接口)。
  • “最佳”?最适合什么?速度?复杂?灵活性?费用?

标签: python json pickle


【解决方案1】:

JSON 还是 pickle? JSON 泡菜怎么样!

您可以使用jsonpickle。它易于使用,并且磁盘上的文件是可读的,因为它是 JSON。

jsonpickle Documentation

【讨论】:

  • 任何人都针对选项的性能进行了基准测试?它在性能上是否与此处所见benfrederickson.com/dont-pickle-your-data 中的原始 json 相当?
  • 这不是一个范围广泛的基准测试,但我有一个现有的游戏,它使用 pickle (python3) 保存关卡。我想尝试使用 jsonpickle 来实现人类可读的方面 - 但是可悲的是,关卡保存速度要慢得多。 jsonpickle 为 1597 毫秒,关卡保存为 88 毫秒或常规泡菜。对于关卡负载,jsonpickle 为 1604 毫秒,pickle 为 388。可惜我喜欢人类可读的保存。
  • 我在我们的交易系统中对此进行了测试,与 pickle 相比,可读性大约是序列化 + 反序列化速度的 2 倍。不过,其他任何东西都很棒。
【解决方案2】:

如果您没有任何互操作性要求(例如,您只是将数据与 Python 一起使用)并且二进制格式很好,请使用cPickle,它可以为您提供非常快速的 Python 对象序列化。

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

【讨论】:

  • JSON seems to be faster 比 cPickle.
  • 我的回答强调了我认为在选择任一解决方案时最需要考虑的问题。我没有声称任何一个都比另一个更快。如果 JSON 更快并且更合适,请使用 JSON! (即,您没有理由投反对票。)
  • 我的观点是:没有真正的理由根据您的前提使用cPickle(或pickle)而不是JSON。当我第一次阅读您的答案时,我认为原因可能是速度,但因为事实并非如此...... :)
  • @mac 引用的基准只测试字符串。我分别测试了str、int和float,发现json在float序列化时比cPickle慢,但在float反序列化时更快。对于 int(和 str),json 两种方式都更快。数据及代码:gist.github.com/marians/f1314446b8bf4d34e782
  • cPickle 的最新协议现在比 JSON 更快。关于 JSON 更快的评论已经过时了几年。 stackoverflow.com/a/39607169/1007353
【解决方案3】:

我尝试了几种方法,发现使用 cPickle 并将转储方法的协议参数设置为: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】:

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

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


其他答案中引用的测试结果是2010年记录的,2016年更新的测试用cPickleprotocol 2显示:

  • cPickle 加载速度提高 3.8 倍
  • cPickle 读取速度提高 1.5 倍
  • cPickle 编码略小

自己使用this gist 重现此内容,它基于其他答案中引用的Konstantin's benchmark,但使用带有协议 2 的 cPickle 而不是 pickle,并使用 json 而不是 simplejson(因为 json 比 simplejson 更快),例如

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   -

Python 3.4 with pickle protocol 3 is even faster.

【讨论】:

    【解决方案5】:

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

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

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

    【讨论】:

    【解决方案6】:

    您可能还会发现这很有趣,可以比较一些图表:http://kovshenin.com/archives/pickle-vs-json-which-is-faster/

    【讨论】:

    【解决方案7】:

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

    【讨论】:

    • 谢谢。无论如何,我会在同一个程序中转储和加载。
    • 虽然在您当前的应用程序中安全风险可能很低,但 JSON 允许您完全关闭整个应用程序。
    • 人们可以创建一种泡菜病毒,它会在加载后将自己腌制到所有被腌制的东西中。使用 json 这是不可能的。
    • 除了安全性之外,JSON 还有一个额外的优势,它使迁移变得容易,因此您可以加载由旧版本的应用程序保存的数据。同时,您可以添加一个字段,或替换整个子结构。为 dict/list 编写这样的转换器(迁移)是直截了当的,但如果使用 Pickle,您将很难在开始考虑转换之前加载它。
    • 我没有考虑过这方面(安全性和腌制对象运行任意代码的能力)。感谢您指出这一点!
    猜你喜欢
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多