前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[技巧篇] 创建百万级实例如何节省内存?

[技巧篇] 创建百万级实例如何节省内存?

作者头像
编程文青李狗蛋
发布2019-07-31 17:04:41
5560
发布2019-07-31 17:04:41
举报

在实际工作中,我们可能会面临创建百万级别量实例的这种情况,比如在某流行社交网络中,定义了用户类 User(id, name, sex, status, ...),每当有一个用户上线的时候,就在服务器内创建一个 User 实例。

这样当在线人数多的时候,很容易就会产生百万千万级别的实例,内存的开销十分巨大,如何降低这些大量实例的内存空间成了我们亟待解决的问题。

这篇文章,我就介绍一种解决办法:定义类的 __slot__ 属性,用它来声明实例属性的列表,可以用来减少内存空间的目的。

首先,我们先定义一个普通的 User 类:

class User1:
     def __init__(self, id, name, sex, status):
         self.id = id
         self.name = name
         self.sex = sex
         self.status = status

然后再定义一个带 __slot__ 的类:

class User2:
     __slots__ = ['id', 'name', 'sex', 'status']
     def __init__(self, id, name, sex, status):
         self.id = id
         self.name = name
         self.sex = sex
         self.status = status

接下来创建两个类的实例:

u1 = User1('01', 'rocky', '男', 1)
u2 = User1('02', 'leey', '男', 1)

我们已经知道 u1 比 u2 使用的内存多,我们可以这样来想,一定是 u1 比 u2 多了某些属性,我们分别来看一下 u1 和 u2 的属性:

['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', 'id', 'name', 'sex', 'status']
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slots__', '__str__', '__subclasshook__', 'id', 'name', 'sex', 'status']

乍一看好像差别不大,我们下面具体来看一下差别在哪:

set(dir(u1)) - set(dir(u2))

通过做集合的差集,我们得到 u1 和 u2 在属性上的具体差别:

{'__weakref__', '__dict__'}

在我们不使用弱引用的时候,__weakref__ 并不占用多少内存,那最终这个锅就要 __dict__ 来背了。

下面我们来看一下 __dict__:

u1.__dict__

输出结果如下所示:

{'id': '01', 'name': 'rocky', 'sex': '男', 'status': 1}

输出一个字典,在它内部我们发现了刚刚在类里定义的属性,这个字典就是为了实例动态绑定属性的一个字典,我们怎么动态绑定呢?比如我们现在没有 u1.level 这个属性,那么我们可以为它动态绑定一个 level 属性,比如 u1.level = 10,然后我们再来考察这个字典:

u1.__dict__

现在输出的结果为:

{'id': '01', 'name': 'rocky', 'sex': '男', 'status': 1, 'level': 10}

这样看到 level 进入到这个字典中。

这样一个动态绑定属性的特性,其实是以牺牲内存为代价的,因为这个 __dict__ 它本身是占用内存的,接下来我们来验证这件事情:

import sys
sys.getsizeof(u1.__dict__)

我们用 sys 模块下的 getsizeof 方法,它可以得到一个对象使用的内存:

112

我们可以看到这个字典占用了 112 的字节。反观 u2,它没有了 __dict__ 这个属性,我们想给它添加一个属性,也是被拒绝的。

u2.level = 10

显示的结果如下所示:

AttributeError: 'User2' object has no attribute 'level'
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-07-30,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Python空间 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档