为什么Pickle协议4的文件大小是协议3的两倍而速度没有提升?

6 投票
1 回答
798 浏览
提问于 2025-04-18 08:58

我在测试Python 3.4的时候,发现pickle模块有了新的协议。所以我对比了两个协议的性能。

def test1():
    pickle3=open("pickle3","wb")
    for i in range(1000000):
        pickle.dump(i,pickle3,3)
    pickle3.close()
    pickle3=open("pickle3","rb")
    for i in range(1000000):
        pickle.load(pickle3)

def test2():
    pickle4=open("pickle4","wb")
    for i in range(1000000):
        pickle.dump(i, pickle4,4)
    pickle3.close()
    pickle4=open("pickle4","rb")
    for i in range(1000000):
        pickle.load(pickle4)

测试1的结果:在6.473秒内进行了2000007次函数调用。

测试2的结果:在6.740秒内进行了2000007次函数调用。

协议4的速度比协议3稍微慢一点,但这个差别可以忽略不计。不过,硬盘的使用情况却差别很大。

使用pickle3时,占用了7,868,672字节。

使用pickle4时,占用了16,868,672字节。

这让我觉得很奇怪,我继续深入研究。看了PEP3154后,我大致明白了这个协议的内容。

对于元组(1,2,3,4,5,6,7)在协议3中的表现:

    0: \x80 PROTO      3
    2: (    MARK
    3: K        BININT1    1
    5: K        BININT1    2
    7: K        BININT1    3
    9: K        BININT1    4
   11: K        BININT1    5
   13: K        BININT1    6
   15: K        BININT1    7
   17: t        TUPLE      (MARK at 2)
   18: q    BINPUT     0
   20: .    STOP

对于元组(1,2,3,4,5,6,7)在协议4中的表现:

    0: \x80 PROTO      4
    2: \x95 FRAME      18
   11: (    MARK
   12: K        BININT1    1
   14: K        BININT1    2
   16: K        BININT1    3
   18: K        BININT1    4
   20: K        BININT1    5
   22: K        BININT1    6
   24: K        BININT1    7
   26: t        TUPLE      (MARK at 11)
   27: \x94 MEMOIZE
   28: .    STOP

协议3的解码器在读取到第17个位置之前,无法知道数据的长度。

而在协议4中,从第2个位置到第18个位置,有一个头部信息显示了数据的长度。

不过,我还是不明白,为什么我在极端情况下要付出几乎双倍的硬盘使用量,却速度差不多或者可能更慢?

1 个回答

2

你在处理整数(ints)。对于这么简单的数据类型,提前知道结构的大小其实没有什么好处。可是对于更复杂的结构,知道框架的大小可以大大提高处理速度。此外,协议4对64位系统放宽了很多限制。

撰写回答