2012년 8월 3일 금요일

python 에서 namedtuple 이나 __slots__ 를 썼을때 얼마나 메모리 절약하나

new style class 에 대한 문서를 읽을때 __slots__ 로 메모리를 절약할수 있다고 하길래 가능하면 이걸 쓰고 있었는데 얼마나 효과가 있나 돌려봤다. 사정상 요즘 자주 쓰는 namedtuple 도 같이 비교해봤음.

테스트 환경


/tmp/x $ uname -a
Linux nude 3.2.0-27-generic #43-Ubuntu SMP Fri Jul 6 14:25:57 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux
/tmp/x $ python -V
Python 2.7.3
/tmp/x $ 


소스


# -*- coding: utf-8 -*-
import sys
import os
import subprocess
import collections

def mem():
    p = subprocess.Popen(["ps", "-p", str(os.getpid()), "-o", "rss"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    print "rss:", (p.stdout.read().split("\n")[1])

class OldStyleClass:
    def __init__(self,a,b,c,d,e,f):
        self.a,self.b,self.c,self.d,self.e,self.f = a,b,c,d,e,f

NamedTuple = collections.namedtuple("NamedTuple", "a b c d e f")

class NewStyleClassWithSlots(object):
    __slots__ = "a b c d e f".split()
    def __init__(self,a,b,c,d,e,f):
        self.a,self.b,self.c,self.d,self.e,self.f = a,b,c,d,e,f

class NewStyleClass(object):
    def __init__(self,a,b,c,d,e,f):
        self.a,self.b,self.c,self.d,self.e,self.f = a,b,c,d,e,f

def test(cnt,cls):
    print cls
    t = eval(cls)
    l = [t(i,i,i,i,i,i) for i in xrange(cnt)]
    mem()

if __name__ == "__main__":
    test(int(sys.argv[1]), sys.argv[2])


결과

/tmp/x $ time python a.py 1000000 OldStyleClass
OldStyleClass
rss: 1157332
1.984 secs
/tmp/x $ time python a.py 1000000 NamedTuple
NamedTuple
rss: 150764
1.139 secs
/tmp/x $ time python a.py 1000000 NewStyleClassWithSlots
NewStyleClassWithSlots
rss: 134424
1.217 secs
/tmp/x $ time python a.py 1000000 NewStyleClass
NewStyleClass
rss: 1149272
2.083 secs
/tmp/x $ 


추가, 걍 tuple


/tmp/x $ time python a.py 1000000 "lambda *x: x"
lambda *x: x
rss: 144848
0.343 secs