Делает ли буферный кэш linux Python cPickle более эффективным, чем shelve? - PullRequest
3 голосов
/ 31 октября 2010

Является ли IO более эффективным из-за буферного кеша на Linux, при хранении часто используемых объектов python в виде отдельных файлов cPickle вместо хранения всех объектов на одной большой полке?

Работает ли дисковый буферный кэш по-разному в этих двух сценариях с точки зрения эффективности?

Могут быть тысячи больших файлов (обычно около 100 МБ, но иногда 1 ГБ), но много ОЗУ (например,64 Гб).

1 Ответ

2 голосов
/ 31 октября 2010

Я не знаю ни одного теоретического способа решить, какой метод быстрее, и даже если бы я это сделал, я не уверен, что доверю этому. Итак, давайте напишем некоторый код и протестируем его.

Если мы упаковываем наши менеджеры pickle / shelve в классы с общим интерфейсом, тогда их будет легко поменять местами в коде. Поэтому, если в какой-то момент в будущем вы обнаружите, что один лучше другого (или обнаружите какой-то еще лучший способ), все, что вам нужно сделать, это написать класс с тем же интерфейсом, и вы сможете подключить новый класс к своему коду с помощью очень мало модификаций для всего остального.

test.py:

import cPickle
import shelve
import os

class PickleManager(object):
    def store(self,name,value):
        with open(name,'w') as f:
            cPickle.dump(value,f)
    def load(self,name):
        with open(name,'r') as f:
            return cPickle.load(f)

class ShelveManager(object):
    def __enter__(self):
        if os.path.exists(self.fname):
            self.shelf=shelve.open(self.fname)
        else:
            self.shelf=shelve.open(self.fname,'n')
        return self
    def __exit__(self,ext_type,exc_value,traceback):
        self.shelf.close()
    def __init__(self,fname):
        self.fname=fname
    def store(self,name,value):
        self.shelf[name]=value        
    def load(self,name):
        return self.shelf[name]

def write(manager):                
    for i in range(100):
        fname='/tmp/{i}.dat'.format(i=i)
        data='The sky is so blue'*100
        manager.store(fname,data)
def read(manager):        
    for i in range(100):
        fname='/tmp/{i}.dat'.format(i=i)        
        manager.load(fname)

Обычно вы бы использовали PickleManager, например так:

manager=PickleManager()
manager.load(...)
manager.store(...)

пока вы используете ShelveManager, как это:

with ShelveManager('/tmp/shelve.dat') as manager:        
    manager.load(...)
    manager.store(...)

Но для проверки производительности вы можете сделать что-то вроде этого:

python -mtimeit -s'import test' 'with test.ShelveManager("/tmp/shelve.dat") as s: test.read(s)'
python -mtimeit -s'import test' 'test.read(test.PickleManager())'
python -mtimeit -s'import test' 'with test.ShelveManager("/tmp/shelve.dat") as s: test.write(s)'
python -mtimeit -s'import test' 'test.write(test.PickleManager())'

По крайней мере, на моей машине результаты выглядят так:

                  read (ms)     write (ms)
PickleManager     9.26          7.92 
ShelveManager     5.32          30.9 

Похоже, что ShelveManager может быть быстрее при чтении, но PickleManager может быть быстрее при записи.

Обязательно запустите эти тесты самостоятельно. Результаты могут меняться в зависимости от версии Python, ОС, типа файловой системы, аппаратного обеспечения и т. Д.

Также обратите внимание, что мои функции write и read генерируют очень маленькие файлы. Вы можете проверить это на данных, более похожих на ваш вариант использования.

...