pythonic - __slots__

Kenneth·2020년 12월 30일
0

pythonic

목록 보기
3/6

python class를 사용할 때, attribute가 고정이라면 memory를 절약하는 방법 - "__slots__"

기본적으로 python class의 instance attribute 는 dict로 저장이 되어 runtime에 임의로 attribute를 추가할 수 있다. 하지만 dict 구현의 특성상 내부적으로 hash table과 hash table을 효율적으로 유지하기 위해 적절한 메모리 공간 (1/2 - 2/3 full) 을 유지하기 때문에, python 3.5까지는 고정적인 구조체보다 33-50% + hash table 크기 정도의 오버헤드를, python 3.6부터는 한 차례 개선되어 PyObject 구조체 포인터 배열 대신 variable_int 배열로 저장해서 낭비가 줄었지만 그래도 추가적으로 공간을 잡고 있는 부분이 있다.

instance 수가 적은 class라면 대세에는 지장 없을 수 있겠지만, instance 수가 많아지고 내부적으로 dict를 활용할 필요가 없을 경우 낭비가 심할 수 있다. 이 때 __slots__를 명시함으로써 낭비없이 필요한 공간을 할당받을 수 있다.

사용 방법은 간단하다.

class X:
    
    __slots__ = ['a', 'b', 'c']  # 매직!
    
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

좀 오래된 사례지만 (dict가 개선되기 전?) 실 서버 환경에서 slots를 정의하는 것 만으로 서버 메모리 사용량을 25.5GB -> 16.2GB 로 대략 40%정도 절약을 보여준 케이스도 있다. (링크).

cpython에서는 필요할 때 직접 추가해줘야 하지만, pypy에서는 자동으로 __slots__ 최적화를 해준다고 한다.

(2021.01.04 추가) instance 수가 적은 경우에는 slots 를 명시하는 비용과 class 에 담을 항목의 개수에 따른 메모리 낭비를 비교할 필요가 있겠다. (예를 들면 양의 1차 함수와 2차 함수를 비교한다 하더라도 x가 발산하지 않는 구간에서는 구체적으로 x와 상수를 계산해서 따져야 하듯.) 우연히 발견한 좀 난해한 에 따르면 slot 1개당 namespace 에 등록기 위해 72byte의 일회성 비용이 있다고 한다.

참조

profile
개발자 + @

0개의 댓글