我注意到使用pickle加载5000个对象的字典需要很长时间(几分钟)-但是加载包含5000个实体的json文件只需要很短的时间(几秒钟)。我知道通常对象带有一些开销-在面向对象编程中,跟踪这些对象的开销是使用它们的成本的一部分。但为什么加载pickled对象需要这么长时间?底层发生了什么事情?序列化对象与仅将其数据写入文件相比有哪些成本? pickle是否将对象恢复到内存中的相同位置或其他位置?(也许将其他对象移开)。如果序列化加载速度较慢(至少pickle是),那么好处是什么?
因此,您基本上是在比较纯Python的反序列化程序和优化的C反序列化程序。即使序列化格式相同,这也不是一个公平的比较。
有一些关于特定对象序列化的速度比较,比较JSON、pickle和cPickle。每种格式下每个对象的速度都会不同。通常情况下,JSON比pickle更快,而且你经常听到不要使用pickle,因为它是不安全的。安全问题和一些速度滞后的原因在于pickle实际上并没有序列化很多数据——相反,它序列化了一些数据和一堆指令,这些指令用于组装Python对象。如果你曾经看过dis
模块,你会看到pickle为每个对象使用的指令类型。cPickle像json一样,并不是纯Python,而是利用了优化的C,所以它通常更快。
总体而言,pickle应该比存储对象本身占用更少的空间——但是,某些指令集可能非常大。JSON倾向于更小……并且是人类可读的……然而,由于json将所有内容都存储为人类可读的字符串……它不能序列化与pickle和cPickle可以序列化的那么多种不同的对象。因此,权衡的是json提供了“安全性”(或者说是灵活性不足,取决于你的观点)和人类可读性,而pickle则可以序列化更广泛的对象。
选择pickle(而不是json)的另一个好处是你可以轻松地扩展pickle,这意味着你可以注册一个新的方法来序列化pickle不知道如何序列化的对象。Python提供了几种方法来实现这一点……例如__getstate__
和__setstate__
以及copy_reg
方法。使用这些方法,你会发现人们已经扩展了pickle以序列化大多数Python对象,例如dill
。
pickling不会将对象恢复到相同的内存位置。然而,它确实重建了对象到与pickle时相同的状态(通常)。如果你想看看为什么人们使用pickle,请看这里:Python serialization - Why pickle?
http://nbviewer.ipython.org/gist/minrk/5241793
http://matthewrocklin.com/blog/work/2013/12/05/Parallelism-and-Serialization/