2012-07-02 11 views
7

Próbuję dokładnie/ostatecznie znaleźć różnice wielkości między dwiema różnymi klasami w Pythonie. Oba są nowymi klasami stylów, z wyjątkiem jednego, który nie ma zdefiniowanych szczelin. Próbowałem wielu testów, aby określić różnice w ich wielkości, ale zawsze są one identyczne w użyciu pamięci.Dokładnie pomierz rozmiar obiektu w Pythonie - nie działa funkcja Sys.GetSizeOf.

Do tej pory próbowałem sys.GetSizeOf (obj) i funkcji heap() heapy, bez pozytywnych wyników. Kod testu jest poniżej:

import sys 
from guppy import hpy 

class test3(object): 
    def __init__(self): 
     self.one = 1 
     self.two = "two variable" 

class test4(object): 
    __slots__ = ('one', 'two') 
    def __init__(self): 
     self.one = 1 
     self.two = "two variable" 

test3_obj = test3() 
print "Sizeof test3_obj", sys.getsizeof(test3_obj) 

test4_obj = test4() 
print "Sizeof test4_obj", sys.getsizeof(test4_obj) 

arr_test3 = [] 
arr_test4 = [] 

for i in range(3000): 
    arr_test3.append(test3()) 
    arr_test4.append(test4()) 

h = hpy() 
print h.heap() 

wyjściowa:

Sizeof test3_obj 32 
Sizeof test4_obj 32 

Partition of a set of 34717 objects. Total size = 2589028 bytes. 
Index Count %  Size % Cumulative % Kind (class/dict of class) 
    0 11896 34 765040 30 765040 30 str 
    1 3001 9 420140 16 1185180 46 dict of __main__.test3 
    2 5573 16 225240 9 1410420 54 tuple 
    3 348 1 167376 6 1577796 61 dict (no owner) 
    4 1567 5 106556 4 1684352 65 types.CodeType 
    5  68 0 105136 4 1789488 69 dict of module 
    6 183 1 97428 4 1886916 73 dict of type 
    7 3001 9 96032 4 1982948 77 __main__.test3 
    8 3001 9 96032 4 2078980 80 __main__.test4 
    9 203 1 90360 3 2169340 84 type 
<99 more rows. Type e.g. '_.more' to view.> 

To wszystko z Python 2.6.0. Ja również próbował zastąpić sizeof metod klasy, aby spróbować ustalić rozmiar poprzez zsumowanie poszczególnych sizeofs ale nie dały różne wyniki:

class test4(object): 
    __slots__ = ('one', 'two') 
    def __init__(self): 
     self.one = 1 
     self.two = "two variable" 
    def __sizeof__(self): 
     return super(test4, self).__sizeof__() + self.one.__sizeof__() + self.two.__sizeof__() 

wyniki z metody sizeof przesłonić:

Sizeof test3_obj 80 
Sizeof test4_obj 80 

Odpowiedz

4

sys.getsizeof zwraca liczbę, która jest bardziej wyspecjalizowane i mniej użyteczne niż ludzie myślą. W rzeczywistości, jeśli zwiększysz liczbę atrybutów do sześciu, twój test3_obj pozostanie na poziomie 32, ale test4_obj przeskoczy do 48 bajtów. Dzieje się tak dlatego, że getsizeof zwraca rozmiar struktury PyObject implementującej typ, który dla test3_obj nie zawiera dyktującego z atrybutami, ale dla test4_obj atrybuty nie są przechowywane w dyktafonie, są przechowywane w slotach, więc są rozliczane w rozmiarze.

Ale klasa zdefiniowana za pomocą __slots__ zajmuje mniej pamięci niż klasa bez, właśnie dlatego, że nie ma dyktatu do przechowywania atrybutów.

Dlaczego zastąpić __sizeof__? Co naprawdę chcesz osiągnąć?

+0

Przesłonięcie sizeof miało na celu sprawdzenie, czy wbudowana metoda sizeof nie poprawnie mierzy rozmiar zmiennych. –

+0

Więc co byś zasugerował, aby najlepiej określić różnice w wielkości między takimi prostymi obiektami? –

+0

To zależy, dlaczego chcesz poznać rozmiar. Jaki problem próbujesz rozwiązać? –

0

Najpierw sprawdź rozmiar procesu Pyton w swoim menedżerze pamięci os 'bez wielu obiektów.

Po drugie zrobić wiele przedmiotów jednego rodzaju i ponownie sprawdzić rozmiar.

Trzecie tworzy wiele obiektów innego rodzaju i sprawdza ich rozmiar.

Powtórz to kilka razy, a jeśli rozmiary każdego kroku pozostaną takie same, uzyskasz coś porównywalnego.

+0

Jestem ciekawy, jaki rodzaj dokładności by mnie dostał? Również ... Potrzebowałbym wydajnego sposobu, aby uruchomić to wiele razy, a następnie, aby to wszystko uśrednić. –

0

Możesz też użyć innej realizacji uzyskania rozmiaru swoich obiektów w pamięci:

>>> import sys, array 
>>> sizeof = lambda obj: sum(map(sys.getsizeof, explore(obj, set()))) 
>>> def explore(obj, memo): 
    loc = id(obj) 
    if loc not in memo: 
     memo.add(loc) 
     yield obj 
     if isinstance(obj, memoryview): 
      yield from explore(obj.obj, memo) 
     elif not isinstance(obj, (range, str, bytes, bytearray, array.array)): 
      # Handle instances with slots. 
      try: 
       slots = obj.__slots__ 
      except AttributeError: 
       pass 
      else: 
       for name in slots: 
        try: 
         attr = getattr(obj, name) 
        except AttributeError: 
         pass 
        else: 
         yield from explore(attr, memo) 
      # Handle instances with dict. 
      try: 
       attrs = obj.__dict__ 
      except AttributeError: 
       pass 
      else: 
       yield from explore(attrs, memo) 
      # Handle dicts or iterables. 
      for name in 'keys', 'values', '__iter__': 
       try: 
        attr = getattr(obj, name) 
       except AttributeError: 
        pass 
       else: 
        for item in attr(): 
         yield from explore(item, memo) 


>>> class Test1: 
    def __init__(self): 
     self.one = 1 
     self.two = 'two variable' 


>>> class Test2: 
    __slots__ = 'one', 'two' 
    def __init__(self): 
     self.one = 1 
     self.two = 'two variable' 


>>> print('sizeof(Test1()) ==', sizeof(Test1())) 
sizeof(Test1()) == 361 
>>> print('sizeof(Test2()) ==', sizeof(Test2())) 
sizeof(Test2()) == 145 
>>> array_test1, array_test2 = [], [] 
>>> for _ in range(3000): 
    array_test1.append(Test1()) 
    array_test2.append(Test2()) 


>>> print('sizeof(array_test1) ==', sizeof(array_test1)) 
sizeof(array_test1) == 530929 
>>> print('sizeof(array_test2) ==', sizeof(array_test2)) 
sizeof(array_test2) == 194825 
>>> 

Wystarczy upewnić się, że nie dają żadnych nieskończone iteratory do tego kodu, jeśli chcesz odpowiedzieć powrotem.

+0

"Wydajność z" Czy nie jest to specyficzna składnia python3? –

+0

Tak, gdy reszta kodu może być uruchamiana przez '2to3.py'. Przeniesienie do miejsca, w którym 'yield from' jest niedostępne, powinno być dość łatwe. –

+0

str nie powinno być iterowane, aby sprawdzić rozmiary ich jednokolorowych podciągów, zaproponowałem edycję, która bierze to pod uwagę. – Adirio

0

Wpadłem na podobny problem i skończyłem pisać własnego pomocnika, który wykonał brudną robotę. Sprawdź to: here

Powiązane problemy