我一直使用pickle,并感到非常满意,但后来我看到了这篇文章:不要用pickle序列化数据
继续阅读后,似乎有以下问题:
- pickle速度较慢
- pickle存在安全隐患
- pickle格式不易于人类阅读
- pickle不具备语言无关性
我已经改用JSON保存我的数据,但我想知道最佳实践:
考虑到所有这些问题,你什么情况下才会使用pickle? 什么特定情况需要使用它?
我一直使用pickle,并感到非常满意,但后来我看到了这篇文章:不要用pickle序列化数据
继续阅读后,似乎有以下问题:
我已经改用JSON保存我的数据,但我想知道最佳实践:
考虑到所有这些问题,你什么情况下才会使用pickle? 什么特定情况需要使用它?
multiprocessing
。安全问题可能适用(但大多数不适用),通用性是绝对必要的,且人类不需要阅读它。你会注意到我完全忽略了“慢”的缺点。这是因为它部分地具有误导性:对于符合JSON模型(字符串、数字、数组、映射)的数据,Pickle确实比较慢,但如果你的数据是这样的,你应该出于其他原因使用JSON。如果你的数据不是这样的(很可能),你还需要考虑将对象转换为JSON数据所需的自定义代码以及将JSON数据转换回对象所需的自定义代码。这增加了工程努力和运行时开销,必须根据情况逐个量化。
multiprocessing
和spark
中,当使用RDDs时,Spark将序列化您定义的用户函数(传递给map、flatMap)使用pickle,因为它可以序列化几乎任何Python对象。 - James LimPickle有方便的优点,它可以在不需要额外工作的情况下序列化任意对象图,并可用于相当广泛的Python类型。尽管如此,在新代码中使用Pickle是不寻常的。JSON更加干净易用。
我尝试了几种方法,发现使用cPickle并将dumps方法的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
我通常不使用Pickle或JSON,而是使用MessagePack,它既安全又快速,并且生成的序列化数据大小小。
另一个优点是可以与其他语言编写的软件交换数据(当然,在JSON的情况下也是如此)。
set
,真遗憾。 - Display Name此外,使用cPickle
而不是Pickle
可以部分解决速度问题。
import json; d = [1]; d.append(d); json.dumps(d)
。 - Anthon