Pergunta

O IO é mais eficiente, devido ao cache do buffer de disco do Linux, ao armazenar objetos python acessados ​​com frequência como arquivos cPickle separados, em vez de armazenar todos os objetos em uma prateleira grande?

O cache do buffer de disco opera de maneira diferente nesses dois cenários em relação à eficiência?

Pode haver milhares de arquivos grandes (geralmente em torno de 100 Mb, mas às vezes 1 Gb), mas muita RAM (por exemplo, 64 Gb).

Foi útil?

Solução

Não conheço nenhuma maneira teórica de decidir qual método é mais rápido e, mesmo que conhecesse, não tenho certeza se confiaria nele.Então, vamos escrever um código e testá-lo.

Se empacotarmos nossos gerenciadores pickle/shelve em classes com uma interface comum, será fácil trocá-los dentro e fora do seu código.Portanto, se em algum momento futuro você descobrir que uma é melhor que a outra (ou descobrir alguma maneira ainda melhor), tudo o que você precisa fazer é escrever uma classe com a mesma interface e você poderá conectar a nova classe ao seu código com muito pouca modificação em qualquer outra coisa.

teste.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)

Normalmente, você usaria o PickleManager assim:

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

enquanto você usaria o ShelveManager assim:

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

Mas para testar o desempenho, você poderia fazer algo assim:

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())'

Pelo menos na minha máquina, os resultados foram assim:

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

Portanto, parece que o ShelveManager pode ser mais rápido na leitura, mas o PickleManager pode ser mais rápido na escrita.

Certifique-se de executar esses testes você mesmo.Os resultados do Timeit podem variar devido à versão do Python, sistema operacional, tipo de sistema de arquivos, hardware, etc.

Além disso, observe meu write e read funções geram arquivos muito pequenos.Você desejará testar isso em dados mais semelhantes ao seu caso de uso.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top