【问题标题】:Python: why pickle?Python:为什么要泡菜?
【发布时间】:2014-03-12 05:08:49
【问题描述】:

一直在用pickle,很开心,后来看到这篇文章:Don't Pickle Your Data

进一步阅读似乎是这样的:

我已将数据保存为 JSON,但我想了解最佳做法:

考虑到所有这些问题,您什么时候会使用泡菜?哪些具体情况需要使用它?

【问题讨论】:

  • 顺便说一句,有些格式比 JSON 更易于人类阅读,并且可以说也更容易编辑。我会想到好的旧 INI 文件和 YAML。它肯定比不透明的二进制流好,但人类可读性不是二进制的东西。
  • 我看到将对象保存为 JSON 的第一个缺点:您必须创建序列化程序,这需要一些时间。再加上 JSON 序列化过程的速度最终可能会比简单的泡菜慢。虽然我同意安全方面的缺点。还有一点是:为什么要存储一个对象并让它可以编辑?那岂不是不安全?
  • 有螺丝刀为什么还要用锤子?有锤子为什么要用螺丝刀?关键在于为手头的工作选择合适的工具。
  • 这与stackoverflow.com/questions/8968884/…基本相同。如果您担心安全性,请不要依赖 pickle 或 JSON。使用更强大的身份验证服务——带有加密密钥的东西。
  • 鉴于 pickle 必须做的额外工作(与 JSON 等过度简化的格式相比)以确保找到对已经表示的对象的引用,它一点也不慢。而 json 即使在像import json; d = [1]; d.append(d); json.dumps(d) 这样非常简单的事情上也会引发错误

标签: python pickle


【解决方案1】:

我尝试了几种方法,发现使用 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

因此,在需要实时性能的情况下,例如从摄像机流式传输视频到 服务器。

【讨论】:

    【解决方案2】:

    我一般既不使用Pickle,也不使用JSON,但是MessagePack既安全又快速,并且产生的序列化数据很小。

    另一个优势是可以与用其他语言编写的软件交换数据(当然,在 JSON 的情况下也是如此)。

    【讨论】:

    • JSON 的最大优势恕我直言,它既简洁(不像 XML)又是人类可读的(不像 MessagePack)。我不确定 MessagePack 节省的大小是否足以抵消这两个好处。
    • 它不像 MessagePack 中的大小节省那么多,但您可以对 JSON 不擅长的东西进行编码,例如二进制数据。
    • MessagePack 无法序列化sets,太可惜了
    【解决方案3】:

    Pickle 是不安全的,因为它通过调用任意函数来构造任意 Python 对象。然而,这也使它能够序列化几乎任何 Python 对象,而无需任何样板文件甚至白/黑名单(在常见情况下)。这对于某些用例来说是非常可取的:

    • 快速简单的序列化,例如用于暂停和恢复长时间运行但简单的脚本。这里没有任何问题,您只想按原样转储程序的状态并稍后加载。
    • 将任意 Python 数据发送到其他进程或计算机,如multiprocessing。安全问题可能适用(但大多数情况下不适用),通用性是绝对必要的,人类不必阅读它。

    在其他情况下,这些缺点都不足以证明将您的内容映射到 JSON 或其他限制性数据模型的工作是合理的。也许您不希望需要人类可读性/安全性/跨语言兼容性,或者您可以不需要。记住,你不需要它。使用 JSON 是正确的事情™,但正确并不总是等于好的。

    您会注意到我完全忽略了“慢”的缺点。这是因为它具有部分误导性:对于完全适合 JSON 模型(字符串、数字、数组、映射)的数据,Pickle 确实较慢,但是如果您的数据是这样的,则无论如何您都应该出于其他原因使用 JSON。如果您的数据不是这样(很可能),您还需要考虑将对象转换为 JSON 数据所需的自定义代码,以及将 JSON 数据转换回您的数据所需的自定义代码对象。它增加了工程工作量和运行时开销,必须根据具体情况进行量化。

    【讨论】:

    • 感谢您的精彩回答。很高兴知道什么是正确的™,即使它并不总是 == 好
    • multiprocessing 和 spark 中。使用 RDD 时,spark 将序列化您的用户定义函数(传递给 map、flatmap)using pickle,因为它几乎可以序列化任何 python 对象。
    【解决方案4】:

    您可以在JSON vs. Pickle security 上找到一些答案:JSON 只能腌制 unicode、int、float、NoneType、bool、list 和 dict。如果要腌制更高级的对象(例如类实例),则不能使用它。请注意,对于这些泡菜,不可能与语言无关。

    也使用cPickle 代替Pickle 部分解决速度进度。

    【讨论】:

    【解决方案5】:

    Pickle 具有方便的优势——它可以序列化任意对象图而无需额外工作,并且适用于相当广泛的 Python 类型。话虽如此,我在新代码中使用 Pickle 是不寻常的。 JSON 使用起来更加简洁。

    【讨论】:

      猜你喜欢
      • 2012-12-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-09
      • 2013-09-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多