2016-03-24 55 views
0

我有一些熊猫数据框,我可以使用.to_pickle()保存到磁盘。这样的对象是200k-700k。Python Pickle占用多少内存?

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

默认情况下,memcached只允许值高达1MB。我发现试图缓存我的200k数据框可以正常工作,但是60万个不会在Python memcache级别设置(客户端甚至不会发出set命令,除非我在memcached上使用-I,并相应地为我的Python设置memcache.SERVER_MAX_VALUE_LENGTH客户)。

将大约100个这样的数据帧存储到memcache中,-I 5m允许它们全部适合,并且在写入pickle文件的磁盘上占用36MB(36212字节)。每memcached的stats命令,我看到几乎3倍的字节都被写入,

STAT bytes_read 89917017 
STAT bytes_written 89917211 
... 
STAT bytes 53022739 

它是那么奇怪的是只有53MB的存储,如果89MB写。

如果我改变我的memcaching代码,以酸洗DataFrames 第一(即写入与.to_pickle()一个临时文件,读取临时文件存储到内存缓存),我看到每个内存缓存stats数据大小匹配什么是磁盘上时,我店相同的文件。

STAT bytes_read 36892901 
STAT bytes_written 36893095 
... 
STAT bytes 36896667 

用于存储酸洗对象的内存与其在磁盘上的大小相比的比例是多少?为什么python memcache不能像使用.to_pickle()一样将DataFrames转换为更小的pickle大小呢?

+0

Pickle可能不是存储DataFrame的最佳选择。为什么不把它们存储为CSV或其他更广泛使用的格式? – BrenBarn

+0

我花了一些时间探索。我会在下面回答我自己的问题。以CSV格式存储(奇怪)几乎与二进制酸洗一样小。 – hamx0r

+0

您对导出格式有什么目标/要求?如果你希望它很小,你最好使用像msgpack这样的格式。根据你的自我回答,目前还不清楚你为什么使用泡菜。 – BrenBarn

回答

0

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

我的解决方法,用大熊猫做二进制酸洗memcaching是这样的(我还添加了namespace ARG很像谷歌应用程序引擎,以帮助确保键唯一使用不同的应用程序相同的内存缓存时)之前:

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的这种用法在写入磁盘时会减慢速度,但测试表明它的速度是将磁盘存储到磁盘并从那里加载它的两倍。

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

最后,python-memcached构造函数采用pickleProtocol ARG其中,如果设置为2,将使用相同的酸洗协议熊猫to_pickle()一样。

pickleProtocol=2min_compress_len=1(始终导致压缩)相结合导致的内存使用量约为单独使用二进制酸洗时的25%,压缩开销增加了运行时间约13%,以将所有数据帧写入内存缓存。