2016-03-24 4 views
0

У меня есть некоторые панды DataFrames, которые я могу сэкономить на диске с помощью .to_pickle(). Такой объект составляет 200k-700k.Сколько памяти занимает Python Pickle?

Я вижу от memcache.py in the Python-memcache github project, он разводит объекты и сжимает их перед кешированием.

По умолчанию memcached допускает только значения до 1 МБ. Я считаю, что попытка кэшировать мои 200k DataFrames работает нормально, но 600k не устанавливаются на уровне memcache Python (клиент даже не выдает команду set, если я не использую -I на memcached и не устанавливаю memcache.SERVER_MAX_VALUE_LENGTH соответственно для моего Python клиент).

Хранение ~ 100 таких данных для memcache с помощью -I 5m позволяет им все в порядке и занимает 36 МБ (36212 байт) на диске с записанными файлами pickle. Per Memcached stats команды, я вижу почти 3x байты были написаны,

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

Это то странно, что только 53MB хранятся, если 89MB были написаны.

Если я изменить мой memcaching код замариновать в DataFrames первый (т.е. запись в TempFile с .to_pickle(), прочитал, что временный файл для хранения в кэше), я вижу размеры данных в кэше stats соответствие, что на диске, когда я хранить те же файлы.

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

Каково соотношение памяти, используемой для хранения маринованного объекта, по сравнению с его размером на диске? И почему бы не использовать memcache python аналогично эффективную работу по преобразованию DataFrames в меньшие размеры рассола, используя .to_pickle()?

+0

Рассол не может быть лучшим выбором для хранения DataFrames. Почему бы просто не хранить их как CSV или какой-либо другой более широко используемый формат? – BrenBarn

+0

Я потратил еще некоторое время на изучение. Я отвечу на свой вопрос ниже. Хранение как CSV (как ни странно) почти такое же, как травление в двоичном формате. – hamx0r

+0

Каковы ваши цели/требования к формату экспорта? Если вы хотите, чтобы он был небольшим, вам может быть лучше использовать формат, например msgpack. Основываясь на вашем собственном ответе ниже, мне все еще не ясно, почему вы используете маринование вообще. – BrenBarn

ответ

0

Кажется, что python-memcache использует кодировку ASCII, когда он соленья объектов, в то время как панды to_pickle() использует рассол v2 в бинарного кодирования, который меньше. Если бы я экспортировал свои данные в CSV в предложение @ BrenBarn, я бы получил файлы, немного большие, чем двоичные данные, но все же ~ 1/3 размер ASCII-маринованного фрейма.

Мой обходной путь использовать панд, чтобы сделать бинарный травление, прежде чем memcaching идет как это (я также добавил namespace агд так же, как Google App Engine, чтобы гарантировать уникальность ключа при использовании же кэша памяти для различных приложений):

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) 

Может показаться, что это использование временного файла замедлит работу, поскольку оно записывает на диск, но тест показывает, что он равен 2x так же быстро, как просто хранение соленья на диске и загрузка их оттуда.

Рассматривая код python-memcached, я вижу, что можно использовать set(min_compress_len=X), чтобы вызвать python-memcache, чтобы сжать значения перед их настройкой. Использование этого метода уменьшило память до 40% от того, что сделал мой предварительный трюк.

Наконец, python-memcached конструктор принимает pickleProtocol ARG, который, если установлены в 2, будет использовать ту же травильную панду протокола to_pickle() делает.

Сочетание pickleProtocol=2 с min_compress_len=1 (чтобы вызвать сжатие всегда) привело к тому, что использование памяти было примерно на 25% от того, что было с бинарным травлением в одиночку, а накладные расходы для сжатия добавили около 13% к времени выполнения, чтобы записать все мои данные Memcache.

Смежные вопросы