当前位置: 首页 > news >正文

python如何优化内存_如何优化Python占用的内存

概述

如果程序处理的数据比较多、比较复杂,那么在程序运行的时候,会占用大量的内存,当内存占用到达一定的数值,程序就有可能被操作系统终止,特别是在限制程序所使用的内存大小的场景,更容易发生问题。下面我就给出几个优化Python占用内存的几个方法。

说明:以下代码运行在Python3。

举个栗子

我们举个简单的场景,使用Python存储一个三维坐标数据,x,y,z。

Dict

使用Python内置的数据结构Dict来实现上述例子的需求很简单。

>>> ob = {'x':1, 'y':2, 'z':3}

>>> x = ob['x']

>>> ob['y'] = y

查看以下ob这个对象占用的内存大小:

>>> print(sys.getsizeof(ob))

240

简单的三个整数,占用的内存还真不少,想象以下,如果有大量的这样的数据要存储,会占用更大的内存。

数据量

占用内存大小1 000 000

240 Mb

10 000 000

2.40 Gb

100 000 000

24 Gb

Class

对于喜欢面向对象编程的程序员来说,更喜欢把数据包在一个class里。使用class使用同样需求:

class Point:

#

def __init__(self, x, y, z):

self.x = x

self.y = y

self.z = z

>>> ob = Point(1,2,3)

class的数据结构和Dict区别就很大了,我们来看看这种情况下占用内存的情况:

字段

占用内存PyGC_Head

24

PyObject_HEAD

16

_weakref_

8

_dict_

8

TOTAL

56

关于 _weakref_(弱引用)可以查看这个文档, 对象的__dict__中存储了一些self.xxx的一些东西。从Python 3.3开始,key使用了共享内存存储, 减少了RAM中实例跟踪的大小。

>>> print(sys.getsizeof(ob), sys.getsizeof(ob.__dict__))

56 112

数据量

占用内存1 000 000

168 Mb

10 000 000

1.68 Gb

100 000 000

16.8 Gb

可以看到内存占用量,class比dict少了一些,但这远远不够。

_slots_

从class的内存占用分布上,我们可以发现,通过消除__dict__和_weakref__,可以显着减少RAM中类实例的大小,我们可以通过使用__slots__来达到这个目的。

class Point:

__slots__ = 'x', 'y', 'z'

def __init__(self, x, y, z):

self.x = x

self.y = y

self.z = z

>>> ob = Point(1,2,3)

>>> print(sys.getsizeof(ob))

64

可以看到内存占用显著的减少了

字段

内存占用PyGC_Head

24

PyObject_HEAD

16

x

8

y

8

z

8

TOTAL

64

数据量

占用内存1 000 000

64Mb

10 000 000

640Mb

100 000 000

6.4Gb

默认情况下,Python的新式类和经典类的实例都有一个dict来存储实例的属性。这在一般情况下还不错,而且非常灵活,乃至在程序中可以随意设置新的属性。但是,对一些在”编译”前就知道有几个固定属性的小class来说,这个dict就有点浪费内存了。

当需要创建大量实例的时候,这个问题变得尤为突出。一种解决方法是在新式类中定义一个__slots__属性。

__slots__声明中包含若干实例变量,并为每个实例预留恰好足够的空间来保存每个变量;这样Python就不会再使用dict,从而节省空间。

那么用slot就是非非常那个有必要吗?使用__slots__也是有副作用的:

每个继承的子类都要重新定义一遍__slots__

实例只能包含哪些在__slots__定义的属性,这对写程序的灵活性有影响,比如你由于某个原因新网给instance设置一个新的属性,比如instance.a = 1, 但是由于a不在__slots__里面就直接报错了,你得不断地去修改__slots__或者用其他方法迂回的解决

实例不能有弱引用(weakref)目标,否则要记得把__weakref__放进__slots__

最后,namedlist和attrs提供了自动创建带__slot__的类,感兴趣的可以试试看。

Tuple

Python还有一个内置类型元组,用于表示不可变数据结构。 元组是固定的结构或记录,但没有字段名称。 对于字段访问,使用字段索引。 在创建元组实例时,元组字段一次性与值对象关联:

>>> ob = (1,2,3)

>>> x = ob[0]

>>> ob[1] = y # ERROR

元组的示例很简洁:

>>> print(sys.getsizeof(ob))

72

可以看只比__slot__多8byte:

字段

占用内存(bytes)PyGC_Head

24

PyObject_HEAD

16

ob_size

8

[0]

8

[1]

8

[2]

8

TOTAL

72

Namedtuple

通过namedtuple我们也可以实现通过key值来访问tuple里的元素:

Point = namedtuple('Point', ('x', 'y', 'z'))

它创建了一个元组的子类,其中定义了用于按名称访问字段的描述符。 对于我们的例子,它看起来像这样:

class Point(tuple):

#

@property

def _get_x(self):

return self[0]

@property

def _get_y(self):

return self[1]

@property

def _get_y(self):

return self[2]

#

def __new__(cls, x, y, z):

return tuple.__new__(cls, (x, y, z))

此类的所有实例都具有与元组相同的内存占用。 大量实例会留下稍大的内存占用:

数据量

内存占用1 000 000

72 Mb

10 000 000

720 Mb

100 000 000

7.2 Gb

Recordclass

python的第三方库recordclassd提供了一个数据结构recordclass.mutabletuple,它几乎和内置tuple数据结构一致,但是占用更少的内存。

>>> Point = recordclass('Point', ('x', 'y', 'z'))

>>> ob = Point(1, 2, 3)

实例化以后,只少了PyGC_Head:

字段

占用内存PyObject_HEAD

16

ob_size

8

x

8

y

8

y

8

TOTAL

48

到此,我们可以看到,和__slot__比,又进一步缩小了内存占用:

数据量

内存占用1 000 000

48 Mb

10 000 000

480 Mb

100 000 000

4.8 Gb

Dataobject

recordclass提供了另外一个解决方法:在内存中使用与__slots__类相同的存储结构,但不参与循环垃圾收集机制。通过recordclass.make_dataclass可以创建出这样的实例:

>>> Point = make_dataclass('Point', ('x', 'y', 'z'))

另外一个方法是继承自dataobject

class Point(dataobject):

x:int

y:int

z:int

以这种方式创建的类将创建不参与循环垃圾收集机制的实例。 内存中实例的结构与__slots__的情况相同,但没有PyGC_Head:

字段

内存占用(bytes)PyObject_HEAD

16

x

8

y

8

y

8

TOTAL

40

>>> ob = Point(1,2,3)

>>> print(sys.getsizeof(ob))

40

要访问这些字段,还使用特殊描述符通过其从对象开头的偏移量来访问字段,这些对象位于类字典中:

mappingproxy({'__new__': ,

.......................................

'x': ,

'y': ,

'z': })

数据量

内存占用1 000 000

40 Mb

10 000 000

400 Mb

100 000 000

4.0 Gb

Cython

有一种方法基于Cython的使用。 它的优点是字段可以采用C语言原子类型的值。例如:

cdef class Python:

cdef public int x, y, z

def __init__(self, x, y, z):

self.x = x

self.y = y

self.z = z

这种情况下,占用的内存更小:

>>> ob = Point(1,2,3)

>>> print(sys.getsizeof(ob))

32

内存结构分布如下:

字段

内存占用(bytes)PyObject_HEAD

16

x

4

y

4

y

4

пусто

4

TOTAL

32

数据量

内存占用1 000 000

32 Mb

10 000 000

320 Mb

100 000 000

3.2 Gb

但是,从Python代码访问时,每次都会执行从int到Python对象的转换,反之亦然。

Numpy

在纯Python的环境中,使用Numpy能带来更好的效果,例如:

>>> Point = numpy.dtype(('x', numpy.int32), ('y', numpy.int32), ('z', numpy.int32)])

创建初始值是0的数组:

>>> points = numpy.zeros(N, dtype=Point)

数据量

内存占用1 000 000

12 Mb

10 000 000

120 Mb

100 000 000

1.2 Gb

最后

可以看出,在Python性能优化这方面,还是有很多事情可以做的。Python提供了方便的同时,也需要暂用较多的资源。在不通的场景下,我需要选择不同的处理方法,以便带来更好的性能体验。

更多有趣的文章,请点击我的博客

···················

欢迎关注课程:

相关文章:

  • python functools.reduce使用_Python的functools.reduce用法
  • vue computed 传参_vue生命周期
  • vb.net 循环生成excel的多个sheet_自动生成报告第一弹
  • python从零开始到放弃之二_python从入门到放弃QAQ
  • 安科瑞仪表调试工具_安科瑞ADW系列物联网智能电力仪表——吴玲霞/徐振
  • winform ctrl键单击多选_Ctrl+Shift 组合键用法大全,知道一半以上就是高手!
  • springboot中为何参数拿对象接收总是报错_SpringBoot整合Swagger2
  • sqlconnection对象的open()是否成功_VBA与数据库解决方案第8讲:创建ADO对象,到打开记录集的过程...
  • swing的gui是通过何种模式进行事件响应与监听_一起双网卡服务器被黑引发的勒索事件...
  • mysql上传数据太慢_腾讯云Ubuntu18.04部置Django2系列(四):数据库迁移及导入本地mysql数据...
  • 螺丝上的十字磨没了_螺丝为什么要分为一字和十字螺丝?
  • python3.7 opencv安装_win10 anaconda3(python3.7) 安装 opencv
  • python qt开发保存_【转】python qt(pyqt)的文件打开、文件保存、文件夹选择对话框...
  • 支架预压弹性变形值计算_支架和钢管柱贝雷梁现浇简支箱梁施工,终于找到你!!...
  • python类的成员函数有一个参数_python 面向对象类成员(字段 方法 属性)
  • CentOS7简单部署NFS
  • express.js的介绍及使用
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • JavaScript工作原理(五):深入了解WebSockets,HTTP/2和SSE,以及如何选择
  • JS学习笔记——闭包
  • Linux Process Manage
  • Protobuf3语言指南
  • Python语法速览与机器学习开发环境搭建
  • SQLServer之创建数据库快照
  • vue自定义指令实现v-tap插件
  • 初识 beanstalkd
  • 创建一种深思熟虑的文化
  • 从setTimeout-setInterval看JS线程
  • 后端_ThinkPHP5
  • 每个JavaScript开发人员应阅读的书【1】 - JavaScript: The Good Parts
  • 爬虫进阶 -- 神级程序员:让你的爬虫就像人类的用户行为!
  • 跳前端坑前,先看看这个!!
  • 微信小程序实战练习(仿五洲到家微信版)
  • 在Unity中实现一个简单的消息管理器
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • ​LeetCode解法汇总1410. HTML 实体解析器
  • #14vue3生成表单并跳转到外部地址的方式
  • #if和#ifdef区别
  • #pragma data_seg 共享数据区(转)
  • (4)事件处理——(2)在页面加载的时候执行任务(Performing tasks on page load)...
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (第二周)效能测试
  • (附源码)springboot金融新闻信息服务系统 毕业设计651450
  • (论文阅读26/100)Weakly-supervised learning with convolutional neural networks
  • (免费领源码)python#django#mysql公交线路查询系统85021- 计算机毕业设计项目选题推荐
  • (免费领源码)python#django#mysql校园校园宿舍管理系统84831-计算机毕业设计项目选题推荐
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • (转)创业的注意事项
  • *** 2003
  • .NET Core 2.1路线图
  • .net core 3.0 linux,.NET Core 3.0 的新增功能
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .NET WebClient 类下载部分文件会错误?可能是解压缩的锅
  • .Net 知识杂记