专栏首页Python空间[技巧篇] 创建百万级实例如何节省内存?

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

在实际工作中,我们可能会面临创建百万级别量实例的这种情况,比如在某流行社交网络中,定义了用户类 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'

本文分享自微信公众号 - Python空间(Devtogether),作者:Rocky0429

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-07-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Python 操作 MongoDB 数据库(下)

    在 Python 操作 MongoDB 数据库(上) 这篇文章中,我们学洗了 MongoDB 数据库的安装运行和使用,以及用 Python 连接 MongoDB...

    Rocky0429
  • 零基础学习 Python 之继承(一)

    面向对象的程序设计都三个主要的特征:封装,继承,多态,这个也是类里面的重要内容,这三个特征我会从今天开始依次开始写,今天我们先来看第一个:「封装」,这一部分我会...

    Rocky0429
  • 写个“类”就是这么 so easy

    在昨天的文章中(我与“类”的初次相见)我们学习了类的基本概念,并用伪代码简单的了解了类的基本的写法和形式,从现在开始我们不用伪代码了,开始用真正的 Python...

    Rocky0429
  • JavaWeb——Struts2

    Struts2是一个基于MVC设计模式web应用框架,在webwork框架技术基础上,Strurts2核心是拦截器,Struts2框架的核心功能都依靠拦截器实现...

    羊羽shine
  • python爬虫入门:获取在百度图片搜索的时候第一页的所有图片并下载

    V站CEO-西顾
  • cssjshtml echart世界地图

    葫芦
  • 快速学习Linux-关机和重启命令

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    cwl_java
  • EL函数以及自定义标签的应用

    一、EL函数(调用普通类的静态方法) 编写步骤(自定义EL函数的编写步骤即自定义标签的编写步骤): ①编写一个普通的java类,提供一个静态方法,功能自定...

    欠扁的小篮子
  • scikit-image图像处理入门

    skimage是纯python语言实现的BSD许可开源图像处理算法库,主要的优势在于:

    AI算法与图像处理
  • scikit-image图像处理入门

    skimage是纯python语言实现的BSD许可开源图像处理算法库,主要的优势在于:

    OpenCV学堂

扫码关注云+社区

领取腾讯云代金券