31. 为创建大量实例节省内存

例如,在某网络游戏中,定义了玩家类Player(id, name, level, ...)。每有一个在线玩家,在服务器程序内则有一个Player的实例,当在线人数很多时,将产生大量实例(如百万级)。

要求:降低大量实例的内存开销。

解决方案:

定义类的__slots__属性,声明实例有哪些属性(关闭动态绑定)。


  • 对于类的__slots__属性:
>>> class Player1:
	def __init__(self, uid, name, level):
		self.uid = uid
		self.name = name
		self.level = level

>>> class Player2:
	__slots__ = ['uid', 'name', 'level']
	def __init__(self, uid, name, level):
		self.uid = uid
		self.name = name
		self.level = level

>>> p1 = Player1('0001', 'Jim', 20)

>>> p2 = Player2('0002', 'Jim', 20)
>>> set(dir(p1)) - set(dir(p2))
{'__dict__', '__weakref__'}

>>> p1.x = 100

>>> p1.y = 200

>>> p1.__dict__
{'uid': '0001', 'name': 'Jim', 'level': 20, 'x': 100, 'y': 200}

__weakref__属性用于弱引用,它并不消耗很多内存。弱引用的用途之一是实现大对象的缓存或者映射,由于是缓存或映射,对象不需要独立存在。

>>> import sys

>>> sys.getsizeof(p1.__dict__)
368

>>> sys.getsizeof(p1.uid) + sys.getsizeof(p1.name) + sys.getsizeof(p1.level)
133

>>> sys.getsizeof(p2.uid) + sys.getsizeof(p2.name) + sys.getsizeof(p2.level)
133

主要消耗内存的是__dict__属性,它用于维护动态添加的属性。

>>> p2.x =100
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    p2.x =100
AttributeError: 'Player2' object has no attribute 'x'

>>> p2.name
'Jim'

类的__slots__属性用于声明实例的属性,关闭实例属性的动态添加。


  • 方案示例:
import tracemalloc

class Player1:
	def __init__(self, uid, name, level):
		self.uid = uid
		self.name = name
		self.level = level

class Player2:
	__slots__ = ['uid', 'name', 'level']
	def __init__(self, uid, name, level):
		self.uid = uid
		self.name = name
		self.level = level

tracemalloc.start()             #start
l1 = [Player1(1, 2, 3) for _ in range(100000)]
#l2 = [Player2(1, 2, 3) for _ in range(100000)]
snapshot = tracemalloc.take_snapshot()              #end

top_stats = snapshot.statistics('filename')
for stat in top_stats[:10]:
    print(stat)

注释l2时,运行结果:

0: size=16.8 MiB, count=299996, average=59 B                #占用内存为16.8 MiB
0: size=64 B, count=1, average=64 B

注释l1时,运行结果:

0: size=7056 KiB, count=100002, average=72 B                #占用内存为7056 KiB
0: size=64 B, count=1, average=64 B

由此可见,当创建大量重复实例时,可通过定义类的__slots__属性来节省内存。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值