【问题标题】:Why is dumping with `pickle` much faster than `json`?为什么用 `pickle` 转储比 `json` 快得多?
【发布时间】:2023-03-31 21:00:02
【问题描述】:

这适用于 Python 3.6。

编辑并删除了很多被证明不相关的内容。

我曾认为 jsonpickle 更快,而 Stack Overflow 上的其他答案和 cmets 似乎很多其他人也相信这一点。

我的测试是否洁净?差距比我预期的要大得多。我在非常大的物体上得到了相同的结果。

import json
import pickle
import timeit

file_name = 'foo'
num_tests = 100000

obj = {1: 1}

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 = 'json.dumps(obj)'
setup = 'from __main__ import json, obj'
result = timeit.timeit(command, setup=setup, number=num_tests)
print("json:   %f seconds" % result)

和输出:

pickle: 0.054130 seconds
json:   0.467168 seconds

【问题讨论】:

  • 什么版本的python?
  • 因为JSON 是文本序列化格式,旨在便于人类阅读和移植。 pickle 是一种二进制表示,旨在提高效率,但仅限于 Python。我不知道你为什么期望JSON 更快。
  • 两者都不是为速度而生的——如果您关心快速和紧凑,请考虑msgpack
  • @pingul 我已经更新了代码以在 Python 3 上使用最高的酸洗协议进行测试。使用相对较小的数据结构,我得到了大约 2 倍的加速。我想这种差异会随着物体越大而变得越明显。 Here is the gist

标签: python json benchmarking pickle


【解决方案1】:

我根据您的代码 sn-p 尝试了几种方法,发现使用 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

【讨论】:

  • 对于未来的用户,我用msgpack 0.5.6 和pickle(相当于Python 3 中的cPickle)为Python 3.5 运行了这个,pickle 现在比@987654328 快@:
  • 我尝试了 small dict 并且 msgpack 稍微快了一点。但不是很多。所以我猜pickle 在大多数情况下是更好的选择,如果你使用 python 结构的话。关于 msgpack 和 json 的另一件需要注意的事情是,它在使用转储/加载时实际上可以改变结构,因为例如它将元组转换为列表。 pickle 默认会正确处理。
【解决方案2】:

JSON 以人类可读的方式进行序列化。 pickle 以二进制表示形式序列化。尽管如此,泡菜通常很慢。像 cPickle 这样的变体更快。如果您想要更好的序列化,请使用 msgpack。

【讨论】:

  • 在python3中,pickle == cpickle
【解决方案3】:

您运行了多少次基准测试?在任何情况下,您都需要消除由线程阻塞等引入的随机延迟。您可以通过运行足够多的基准测试来做到这一点。此外,您的输入太小,无法抑制“样板”代码的任何延迟。

【讨论】:

  • 是的,我在本地运行了很多次。对于这个应用程序,测试运行多少次并不重要,因为它是如此(相对)慢,并且两个结果的差异是一个完整的数量级。不要太密集。
  • @user910210 不必无礼。
猜你喜欢
  • 1970-01-01
  • 2014-04-21
  • 2015-02-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-06-18
  • 2011-11-30
相关资源
最近更新 更多