【问题标题】:Python: performance comparison of using `pickle` or `marshal` and using `re`Python:使用`pickle`或`marshal`和使用`re`的性能比较
【发布时间】:2012-03-28 14:21:09
【问题描述】:

我正在使用 Python 计算一些非常大的数字,我想将之前计算的结果存储在 Berkeley DB 中。

问题是Berkeley DB必须使用字符串,我必须为计算结果存储一个整数元组。

例如,我得到(m, n) 作为结果,一种方法是将其存储为"%d,%d" % (m, n) 并使用re 将其读出。我还可以使用picklemarshal 存储元组。

哪个性能更好?

【问题讨论】:

  • 为什么要使用re 来解析它?你为什么关心性能?如果您关心性能,为什么您期望解释保存的数据成为瓶颈?您的“先前计算的结果”的性质是什么?为什么不存储一个包含多个列的元组?从什么时候开始,数据库将您限制为仅使用字符串?这些都没有任何意义。
  • @KarlKnechtel:Berkeley DB 没有列。它是一个键值数据库,是众多数据库之一:Tokyo / Kyoto Cabinet、Memcached、Cassandra、Dynamo、Voldemort 等。
  • @KarlKnechtel 我使用的是 Berkeley DB,所以我没有多列,如果我使用的是其他数据库,我就不用担心了。见stackoverflow.com/questions/2399643/…

标签: python performance serialization deserialization


【解决方案1】:

当有人在考虑性能时,他应该记住 3 件事:

  • 不要相信任何人 - 任何基准都可能撒谎(出于不同的原因:不专业、营销等)
  • 始终衡量您的情况 - 例如,缓存系统和统计数据有完全不同的要求。在一种情况下,您需要尽可能快地阅读,在另一种情况下 - 写
  • 重复测试 - 任何软件的新版本都可能更快/更慢,因此任何更新都可能带来好处/惩罚

例如,这是我的benchmark 的结果:

jimilian$ python3.5 serializators.py
iterations= 100000
data= 'avzvasdklfjhaskldjfhkweljrqlkjb*@&$Y)(!#&$G@#lkjabfsdflb(*!G@#$(GKLJBmnz,bv(PGDFLKJ'
==== DUMP ====
Pickle:
>> 0.09806302400829736
Json: 2.0.9
>> 0.12253901800431777
Marshal: 4
>> 0.09477431800041813
Msgpack: (0, 4, 7)
>> 0.16701826300413813

==== LOAD ====
Pickle:
>> 0.10376790800364688
Json: 2.0.9
>> 0.30041573599737603
Marshal: 4
>> 0.034003349996055476
Msgpack: (0, 4, 7)
>> 0.061493027009419166

jimilian$ python3.5 serializators.py
iterations= 100000
data= [1,2,3]*100
==== DUMP ====
Pickle:
>> 0.9678693519963417
Json: 2.0.9
>> 4.494351467001252
Marshal: 4
>> 0.8597690019960282
Msgpack: (0, 4, 7)
>> 1.2778299400088144

==== LOAD ====
Pickle:
>> 1.0350999219954247
Json: 2.0.9
>> 3.349724347004667
Marshal: 4
>> 0.468191737003508
Msgpack: (0, 4, 7)
>> 0.3629750510008307

jimilian$ python2.7 serializators.py
iterations= 100000
data= [1,2,3]*100
==== DUMP ====
Pickle:
>> 50.5894570351
Json: 2.0.9
>> 2.69190311432
cPickle: 1.71
>> 5.14689707756
Marshal: 2
>> 0.539206981659
Msgpack: (0, 4, 7)
>> 0.752672195435

==== LOAD ====
Pickle:
>> 58.8052768707
Json: 2.0.9
>> 3.50090789795
cPickle: 1.71
>> 8.46298909187
Marshal: 2
>> 0.469168901443
Msgpack: (0, 4, 7)
>> 0.315001010895

所以,正如您所看到的,有时在 python2 中使用 Pickle(python3,长字符串,转储)会更好,有时 - msgpack(python3,长数组,加载) - 事情完全不同。这就是为什么没有人能给出对所有人都有效的肯定答案。

【讨论】:

    【解决方案2】:

    对于纯粹的速度,marshal 将为您带来最快的结果。

    时间安排:

    >>> timeit.timeit("pickle.dumps([1,2,3])","import pickle",number=10000)
    0.2939901351928711
    >>> timeit.timeit("json.dumps([1,2,3])","import json",number=10000)
    0.09756112098693848
    >>> timeit.timeit("pickle.dumps([1,2,3])","import cPickle as pickle",number=10000)
    0.031056880950927734
    >>> timeit.timeit("marshal.dumps([1,2,3])","import marshal", number=10000)
    0.00703883171081543
    

    【讨论】:

    • 事实证明,如果我不希望它是人类可读的,那么 marshal 会更快。
    • 我用 msgpack 测试了 marshal,但 marshal 在速度方面获胜。在一个小列表上编组 15000 次操作的平均时间 = 0.0003171195348103841,相同测试的 msgpack 时间 = 0.0008052133083343506。虽然我没有检查空间使用情况......
    • 请记住来自 marshal 文档的警告:docs.python.org/library/marshal.html 警告 marshal 模块并非旨在防止错误或恶意构造的数据。切勿解组从不受信任或未经身份验证的来源收到的数据。
    • @Urjit 泡菜也是如此。这不是选择其中一个的理由。
    【解决方案3】:

    查看shelve,这是一个简单的持久键值存储,具有类似字典的 API,使用pickle 序列化对象。

    【讨论】:

      【解决方案4】:

      给他们计时并找出答案!

      我希望 cPickle 是最快的,但这不能保证。

      【讨论】:

      • 请注意,OP 没有提到 Python 版本,并且 cPickle 与 Py3 中的 pickle 不分开存在 - pickle 将提供它存在的优化版本,并且下降否则返回纯 python 版本。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 2012-11-03
      • 2019-03-25
      • 2011-10-05
      • 1970-01-01
      • 2019-05-18
      相关资源
      最近更新 更多