문제

위젯의 트리 구조가 있습니다. 예를 들어 컬렉션에는 모델이 포함되어 있으며 모델에는 위젯이 포함되어 있습니다. 전체 컬렉션을 복사하고 싶습니다. copy.deepcopy '피클과 디 픽일'과 비교할 때 더 빠르지 만 C로 쓰여진 CPickle은 훨씬 빠릅니다.

  1. 왜 (우리)가 항상 딥 콥 대신 cpickle을 사용해서는 안됩니까?
  2. 다른 사본 대안이 있습니까? 피클이 느리기 때문에 DeepCopy이지만 CPickle은 더 빠르기 때문에 CPICLE의 C 구현이 될 수 있습니다.

샘플 테스트 코드 :

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

타이밍 :

>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
도움이 되었습니까?

해결책

문제는 Pickle+Unpickle이 더 빠를 수 있다는 것입니다 (C 구현에서). 덜 일반 딥 코피보다 : 많은 물체는 딥 카피이지만 절인 할 수 없습니다. 예를 들어 당신의 수업이라고 가정하십시오 A 변경되었습니다 ... :

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

지금, copy1 여전히 잘 작동합니다 (A의 복잡성은 속도가 느려지지만 절대 멈추지는 않습니다). copy2 그리고 copy3 브레이크, 스택 추적의 끝이 말한다 ... :

  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

예를 들어, 절인 절인은 항상 클래스와 기능이 모듈의 최상위 엔티티라고 가정하고 "이름으로"피킹하는 것은 그러한 가정을 전혀하지 않습니다.

따라서 "다소 깊은 인기"의 속도가 절대적으로 중요한 상황이 있다면, 모든 밀리 초의 모든 문제가 발생하며, 절개하는 대상과 같이 복제중인 객체에 적용되는 특별한 한계를 활용하려고합니다. 적용 가능 또는 다른 형태의 직렬화 및 기타 단축키를 선호하는 사람은 계속 진행됩니다. 그러나 그렇다면, 당신은 당신이 그 한계에 의해 영원히 살아야한다는 것을 제한하고 있으며, 그 결정을 매우 명확하게 문서화하고 있습니다. 미래 유지 관리자의 이익을 위해 명시 적으로.

일반적인 경우 일반적인 경우, 당신이 일반성을 원하는 경우 deepcopy!-)

다른 팁

코드가 더 읽기 쉬워지기 때문에 DeepCopy를 사용해야합니다. 직렬화 메커니즘을 사용하여 메모리에 객체를 복사하는 것은 코드를 읽는 다른 개발자에게 최소한 혼란 스럽습니다. DeepCopy를 사용하면 DeepCopy에서 향후 최적화의 이점을 얻을 수 있습니다.

최적화의 첫 번째 규칙 :하지 마십시오.

그것은이다 ~ 아니다 항상 cpickle이 deepcopy ()보다 빠릅니다. CPickle은 아마도 피클보다 항상 빠르지 만 DeepCopy보다 빠르지 않든

  • 복사 할 구조물의 크기와 중첩 레벨,
  • 포함 된 물체의 유형 및
  • 절인 문자열 표현의 크기.

무언가를 절인 할 수 있다면, 그것은 분명히 심해 할 수 있지만 그 반대는 그렇지 않습니다. 무언가를 피우려면 완전히 직렬화되어야합니다.; 이것은 심해의 경우가 아닙니다. 특히 구현할 수 있습니다 __deepcopy__ 모든 것을 디스크에 저장하지 않고 메모리의 구조를 메모리에서 복사하여 매우 효율적으로 (확장 유형을 생각하십시오). (정지 대-램 대 정지--디스크를 생각해보십시오.)

위의 조건을 충족하는 잘 알려진 확장 유형은 ndarray, 그리고 실제로, 그것은 당신의 관찰에 대한 좋은 반례 역할을합니다. d = numpy.arange(100000000), 코드는 다른 runtimes를 제공합니다.

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

만약에 __deepcopy__ 구현되지 않고 copy 그리고 pickle 공통 인프라 공유 (참조, copy_reg 논의 된 모듈 피클과 심해의 관계).

더 빠르게 사본을 피하는 것이 더 빠릅니다. 당신은 당신이 렌더링을하고 있다고 언급합니다. 객체를 복사 해야하는 이유는 무엇입니까?

짧고 다소 늦었다 :

  • 어쨌든 객체를 cpickle해야한다면 cpickle 방법을 deepcopy에 사용할 수도 있습니다 (그러나 문서).

예를 들어 고려할 수 있습니다.

def mydeepcopy(obj):
    try:
       return cPickle.loads(cPickle.dumps(obj, -1))
    except PicklingError:
       return deepcopy(obj)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top