为啥 python pickle 加载和转储会膨胀磁盘上对象的大小?
Posted
技术标签:
【中文标题】为啥 python pickle 加载和转储会膨胀磁盘上对象的大小?【英文标题】:Why does python pickle load and dump inflate the size of of an object on disk?为什么 python pickle 加载和转储会膨胀磁盘上对象的大小? 【发布时间】:2012-10-11 22:52:30 【问题描述】:我在一个名为 b1.pkl 的文件中有一个腌制对象:
$ ls -l b*
-rw-r--r-- 1 fireball staff 64743950 Oct 11 15:32 b1.pkl
然后我运行以下 python 代码来加载对象并将其转储到一个新文件中:
import numpy as np
import cPickle as pkl
fin = open('b1.pkl', 'r')
fout = open('b2.pkl', 'w')
x = pkl.load(fin)
pkl.dump(x, fout)
fin.close()
fout.close()
这段代码创建的文件是原来的两倍多:
$ ls -l b*
-rw-r--r-- 1 fireball staff 64743950 Oct 11 15:32 b1.pkl
-rw-r--r-- 1 fireball staff 191763914 Oct 11 15:47 b2.pkl
谁能解释一下为什么新文件比原来的大很多?它应该包含完全相同的结构。
【问题讨论】:
原来的泡菜是用相同的协议吗? 【参考方案1】:可能是原来的 pickle 使用了其他协议。例如,尝试将protocol=2
指定为第二个pickle.dump
的关键字参数并再次测试它。二进制泡菜的大小应该小得多。
【讨论】:
我尝试指定protocol=2,结果文件与原始文件大小相同!【参考方案2】:您的原始b1.pkl
很可能是使用更有效的协议模式(1 或 2)挑选出来的。所以你的文件开始变小了。
当您使用 cPickle 加载时,它会自动从文件中为您检测协议。但是,当您使用默认参数再次转储它时,它将使用更大的协议 0。它这样做是为了便携性/兼容性。您需要明确请求二进制协议。
import numpy as np
import cPickle
# random data
s =
for i in xrange(5000):
s[i] = np.random.randn(5,5)
# pickle it out the first time with binary protocol
with open('data.pkl', 'wb') as f:
cPickle.dump(s, f, 2)
# read it back in and pickle it out with default args
with open('data.pkl', 'rb') as f:
with open('data2.pkl', 'wb') as o:
s = cPickle.load(f)
cPickle.dump(s, o)
$ ls -l
1174109 Oct 11 16:05 data.pkl
3243157 Oct 11 16:08 data2.pkl
【讨论】:
当我转储出原件时,我使用了 -1 的 pickle 参数。显然,它在磁盘上产生了更紧凑的表示。我猜它一定是导致python使用protocol=2。【参考方案3】:pkl.dump(x, fout, 2) 可能会产生相同的文件大小。 不指定协议版本将使pickle使用旧版本0。
【讨论】:
以上是关于为啥 python pickle 加载和转储会膨胀磁盘上对象的大小?的主要内容,如果未能解决你的问题,请参考以下文章
使用 Python 的 Pickle 加载时,如何将 module.Class() 替换为本地定义的 Class()?