Python Pickle会占用多少内存?

时间:2016-03-24 02:43:33

标签: python memcached pickle

我有一些pandas DataFrames,我可以使用.to_pickle()保存到磁盘。这样的物体是200k-700k。

我从memcache.py in the Python-memcache github project看到,它在缓存之前腌制对象并压缩它们。

默认情况下,memcached仅允许最大1MB的值。我发现尝试缓存我的200k DataFrames工作正常,但600k的那些没有设置在Python内存缓存级别(客户端甚至不发出set命令,除非我在memcached上使用-I并设置{ {1}}因此我的Python客户端)。

将大约100个这样的数据帧存储到带有memcache.SERVER_MAX_VALUE_LENGTH的内存缓存中,这使得它们全部适合并在磁盘上占用36MB(36212字节)并带有写入的pickle文件。根据memcached -I 5m命令,我看到写入了近3倍的字节,

stats

奇怪的是,如果写入89MB,则只能存储53MB。

如果我改变我的memcaching代码以首先挑选DataFrames (即用STAT bytes_read 89917017 STAT bytes_written 89917211 ... STAT bytes 53022739 写入临时文件,请读取该临时文件以存储到memcache),我看到每个memcache的数据大小.to_pickle()匹配存储相同文件时磁盘上的内容。

stats

用于存储pickle对象的内存与磁盘上的大小比例是多少?为什么python memcache不能像使用STAT bytes_read 36892901 STAT bytes_written 36893095 ... STAT bytes 36896667 一样将DataFrames转换为更小的pickle大小呢?

1 个答案:

答案 0 :(得分:0)

似乎python-memcache在腌制对象时使用ASCII编码,而pandas'to_pickle()二进制编码中使用较小的pickle v2。如果按照@BrenBarn的建议将我的数据帧导出为CSV,我会得到比二进制数据帧略大的文件,但仍然是ASCII-pickled数据帧大小的1/3。

我使用Pandas在memcaching之前进行二进制酸洗的解决方法是这样的(我还添加了namespace与Google App Engine非常相似,以帮助确保在为不同的应用程序使用相同的memcache时的密钥唯一性:

import memcache
import tempfile
import pandas as pd
mc_client = memcache.Client(['localhost:11211'], debug=0)
def mc_get(key, namespace):
    """ Gets pickle from Memecache and converts to a dataframe
    """
    data = mc_client.get('{}_{}'.format(namespace, key))
    if data is None:
        return
    temp_file = tempfile.NamedTemporaryFile()
    temp_file.write(data)
    temp_file.flush()
    return pd.read_pickle(temp_file.name)

def mc_set(key, df, namespace):
    """ Convert dataframe to dict and store it to memcache
    """
    temp_file = tempfile.NamedTemporaryFile()
    df.to_pickle(temp_file.name)
    temp_file.flush()
    data = temp_file.read()
    mc_client.set('{}_{}'.format(namespace, key), data)

看起来这种tempfile的使用会在写入磁盘时减慢速度,但测试显示它只是将pickle存储到磁盘并从那里加载它们的速度的2倍。

查看python-memcached代码,我发现可以使用set(min_compress_len=X)触发python-memcache在设置之前压缩值。使用这种方法可以将内存减少到我的预腌制技巧的40%。

最后,python-memcached构造函数采用pickleProtocol arg,如果设置为2,则会使用与Pandas'to_pickle()相同的酸洗协议。

pickleProtocol=2min_compress_len=1相结合(总是导致压缩)导致内存使用量仅为二进制酸洗的25%左右,压缩开销增加了约13%是时候把我所有的数据帧写到memcache了。