Pergunta

Eu tenho uma estrutura de árvore de widgets, por exemplo, contém modelos e o modelo contém widgets. Eu quero copiar a coleção inteira, copy.deepcopy é mais rápido em comparação com 'picles e descompactar o objeto, mas cpickle como ser escrito em c é muito mais rápido, então

  1. Por que eu não deveria estar sempre usando o CPICKLE em vez de Deepcopy?
  2. Existe alguma outra alternativa de cópia? Porque o picles é mais lento do que o DeepCopy, mas o CPickle é mais rápido, por isso pode ser uma implementação C de Deepcopy será o vencedor

Código de teste de amostra:

import copy
import pickle
import cPickle

class A(object): pass

d = {}
for i in range(1000):
    d[i] = A()

def copy1():
    return copy.deepcopy(d)

def copy2():
    return pickle.loads(pickle.dumps(d, -1))

def copy3():
    return cPickle.loads(cPickle.dumps(d, -1))

Horários:

>python -m timeit -s "import c" "c.copy1()"
10 loops, best of 3: 46.3 msec per loop

>python -m timeit -s "import c" "c.copy2()"
10 loops, best of 3: 93.3 msec per loop

>python -m timeit -s "import c" "c.copy3()"
100 loops, best of 3: 17.1 msec per loop
Foi útil?

Solução

O problema é que o picles+descompacta pode ser mais rápido (na implementação C) porque é menos geral do que o Deepcypy: muitos objetos podem ser profundos, mas não em conserva. Suponha, por exemplo, que sua classe A foram alterados para ...:

class A(object):
  class B(object): pass
  def __init__(self): self.b = self.B()

agora, copy1 Ainda funciona bem (a complexidade de A diminui, mas absolutamente não o impede); copy2 e copy3 Break, o final do rastreamento da pilha diz ...:

  File "./c.py", line 20, in copy3
    return cPickle.loads(cPickle.dumps(d, -1))
PicklingError: Can't pickle <class 'c.B'>: attribute lookup c.B failed

Ou seja, a decapagem sempre assume que as aulas e funções são entidades de alto nível em seus módulos e, portanto, piquetá-las "pelo nome"-o DeepCopying não faz absolutamente essas suposições.

Portanto, se você tem uma situação em que a velocidade de "um tanto profundo" é absolutamente crucial, a cada milissegundo é importante, e você deseja aproveitar as limitações especiais que você conhece se aplica aos objetos que você está duplicando, como aqueles que fazem decapagem aplicável, ou aqueles que favorecem outras formas ainda de serializações e outros atalhos, vá em frente - mas se você deve estar ciente de que está restringindo seu sistema a viver por essas limitações para sempre e documentar essa decisão de design de maneira muito clara e explicitamente para o benefício de futuros mantenedores.

Para o caso normal, onde você deseja generalidade, use deepcopy!-)

Outras dicas

Você deve estar usando o DeepCopy porque torna seu código mais legível. O uso de um mecanismo de serialização para copiar objetos na memória é, no mínimo, confuso para outro desenvolvedor lendo seu código. O uso do Deepcopy também significa que você colhe os benefícios de futuras otimizações em DeepCopy.

Primeira regra de otimização: não.

Isso é não Sempre o caso em que o cpickle é mais rápido que o Deepcopy (). Enquanto o cpickle provavelmente é sempre mais rápido que o picles, seja mais rápido que o DeepCopy depende de

  • o tamanho e o nível de nidificação das estruturas a serem copiadas,
  • o tipo de objetos contidos e
  • O tamanho da representação em conserva em conserva.

Se algo pode ser em conserva, obviamente pode ser profundo, mas o oposto não é o caso: Para apagar alguma coisa, ele precisa ser totalmente serializado; Este não é o caso de Copying. Em particular, você pode implementar __deepcopy__ com muita eficiência copiando uma estrutura na memória (pense nos tipos de extensão), sem poder salvar tudo no disco. (Pense em suspender-to-ram vs. suspender para disco.)

Um tipo de extensão bem conhecido que atende às condições acima pode ser ndarray, e de fato, serve como um bom contra -exemplo à sua observação: com d = numpy.arange(100000000), seu código fornece diferentes tempos de execução:

In [1]: import copy, pickle, cPickle, numpy

In [2]: d = numpy.arange(100000000)

In [3]: %timeit pickle.loads(pickle.dumps(d, -1))
1 loops, best of 3: 2.95 s per loop

In [4]: %timeit cPickle.loads(cPickle.dumps(d, -1))
1 loops, best of 3: 2.37 s per loop

In [5]: %timeit copy.deepcopy(d)
1 loops, best of 3: 459 ms per loop

Se __deepcopy__ não é implementado, copy e pickle Compartilhe a infraestrutura comum (cf. copy_reg módulo, discutido em Relação entre picles e deepcopy).

Ainda mais rápido seria evitar a cópia em primeiro lugar. Você menciona que está fazendo a renderização. Por que ele precisa copiar objetos?

Curto e um pouco tarde:

  • Se você precisar fazer um objeto de qualquer maneira, também pode usar o método cpickle para o DeepCopy (mas documento)

por exemplo, você pode considerar:

def mydeepcopy(obj):
    try:
       return cPickle.loads(cPickle.dumps(obj, -1))
    except PicklingError:
       return deepcopy(obj)
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top