Задать вопрос
@lambakean

Как можно оптимизировать использование памяти при работе с экземплярами классов в Python?

Я пишу игру, в которой есть юниты. Есть класс Unit, который представляет собой хранилище информации о каждом отдельном юните. У класса Unit сейчас такая структура:
class Unit:
    def __init__(self, color, health):
        self.color = color
        self.health = health


При создании юнита я каждый раз создаю экземпляр класса Unit, чтобы потом с легкостью в нужном мне месте получить нужную информацию о любом юните. Значит, если у меня на поле 100 одинаковых юнитов, то одна и та же информация хранится в памяти в 100 экземплярах?

Так как в игре у меня обычно много юнитов, а у каждого юнита по 23 свойства, я подумал, что будет лучше оптимизировать вот так:
class Unit:

    color = (13, 155, 250)
    health = 100

    def __init__(self):
        #Do something
        pass


Во втором примере кода одна и та же информация не хранится в памяти много раз, как я думаю, так как color и health это уже не свойства юнитов, которых сотни, а свойства класса, а класс у нас только один.

Я решил проверить, поможет ли этот способ оптимизировать использование памяти и воспользовался библиотекой guppy3

Сначала я проверил, сколько памяти занимают 10000 юнитов, если использовать первый (неоптимизированный) способ:
from guppy import hpy

'''
Массив со списком всех юнитов, чтобы объекты не уничтожались
из-за того, что на них ничего не ссылается
'''
l = list()

class Unit:
	
	def __init__(self, number, radius, width, color):

		self.number = number
		self.radius = radius
		self.width = width
		self.color = color

		l.append(self)


for i in range(10000):
	''' Создание 10000 юнитов '''
	Unit(i, 4, 1, (13, 150, 255))


h = hpy()
''' Вывод информации о том, сколько места в памяти занимает программа '''
print(h.heap())


В итоге, если верить данным, которые выдает библиотека guppy3, моя программа заняла 5,8 МБ в памяти

Теперь проверим, сколько памяти займет программа, если использовать второй (оптимизированный) способ:

from guppy import hpy

'''
Массив со списком всех юнитов, чтобы объекты не уничтожались
из-за того, что на них ничего не ссылается
'''
l = list()

class Unit:

	radius = 4
	width = 1
	color = (13, 150, 255)
	
	def __init__(self, number):

		self.number = number

		l.append(self)


for i in range(10000):
	''' Создание 10000 юнитов '''
	Unit(i)


h = hpy()
''' Вывод информации о том, сколько места в памяти занимает программа '''
print(h.heap())


В итоге выходит, что вторая программа занимает в памяти почти точь в точь столько же места - 5,8 МБ.

Почему никакой разницы нет? Может "под капотом" python сам оптимизирует это, поэтому результат одинаковый? Или, наоборот, и там, и там одна и та же информация повторяется 10000 раз и нужно искать другой способ исправить это?
  • Вопрос задан
  • 144 просмотра
Подписаться 2 Средний 1 комментарий
Решения вопроса 1
fox_12
@fox_12 Куратор тега Python
Расставляю биты, управляю заряженными частицами
Попробуйте так класс определить:
class Unit:
  __slots__ = ('number', 'radius', 'width', 'color')

  def __init__(self, number, radius, width, color):

    self.number = number
    self.radius = radius
    self.width = width
    self.color = color

    l.append(self)


Без использования __slots__
Partition of a set of 71837 objects. Total size = 6887839 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  10000  14  1120000  16   1120000  16 dict of __main__.Unit
     1  12606  18  1099993  16   2219993  32 str
     2  10056  14   729024  11   2949017  43 tuple
     3  10000  14   560000   8   3509017  51 __main__.Unit
     4    561   1   460680   7   3969697  58 type
     5   2512   3   361909   5   4331606  63 types.CodeType
     6   4892   7   340577   5   4672183  68 bytes
     7   2413   3   328168   5   5000351  73 function
     8  11220  16   317416   5   5317767  77 int
     9    561   1   269392   4   5587159  81 dict of type
<125 more rows. Type e.g. '_.more' to view.>


С использованием __slots__:
Partition of a set of 61841 objects. Total size = 5928031 bytes.
 Index  Count   %     Size   % Cumulative  % Kind (class / dict of class)
     0  12606  20  1099995  19   1099995  19 str
     1  10058  16   729232  12   1829227  31 tuple
     2  10000  16   720000  12   2549227  43 __main__.Unit
     3    561   1   460512   8   3009739  51 type
     4   2512   4   361909   6   3371648  57 types.CodeType
     5   4892   8   340583   6   3712231  63 bytes
     6   2413   4   328168   6   4040399  68 function
     7  11220  18   317416   5   4357815  74 int
     8    561   1   269392   5   4627207  78 dict of type
     9    400   1   181760   3   4808967  81 set
<124 more rows. Type e.g. '_.more' to view.>
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы