提高代码效率的6个Python内存优化技巧

这篇具有很好参考价值的文章主要介绍了提高代码效率的6个Python内存优化技巧。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

当项目变得越来越大时,有效地管理计算资源是一个不可避免的需求。Python与C或c++等低级语言相比,似乎不够节省内存。

但是其实有许多方法可以显著优化Python程序的内存使用,这些方法可能在实际应用中并没有人注意,所以本文将重点介绍Python的内置机制,掌握它们将大大提高Python编程技能。

提高代码效率的6个Python内存优化技巧,python,开发语言,机器学习,内存管理

首先在进行内存优化之前,我们首先要查看内存的使用情况

分配了多少内存?

有几种方法可以在Python中获取对象的大小。可以使用sys.getsizeof()来获取对象的确切大小,使用objgraph.show_refs()来可视化对象的结构,或者使用psutil.Process().memory_info()。RSS获取当前分配的所有内存。

 >>> import numpy as np
 >>> import sys
 >>> import objgraph
 >>> import psutil
 >>> import pandas as pd
 
 
 >>> ob = np.ones((1024, 1024, 1024, 3), dtype=np.uint8)
 
 ### Check object 'ob' size
 >>> sys.getsizeof(ob) / (1024 * 1024)
 3072.0001373291016
 
 ### Check current memory usage of whole process (include ob and installed packages, ...)
 >>> psutil.Process().memory_info().rss / (1024 * 1024)
 3234.19140625
 
 ### Check structure of 'ob' (Useful for class object)
 >>> objgraph.show_refs([ob], filename='sample-graph.png')
 
 ### Check memory for pandas.DataFrame
 >>> from sklearn.datasets import load_boston
 >>> data = load_boston()
 >>> data = pd.DataFrame(data['data'])
 >>> print(data.info(verbose=False, memory_usage='deep'))
 <class 'pandas.core.frame.DataFrame'>
 RangeIndex: 506 entries, 0 to 505
 Columns: 13 entries, 0 to 12
 dtypes: float64(13)
 memory usage: 51.5 KB
   
 ### Check memory for pandas.Series
 >>> data[0].memory_usage(deep=True)   # deep=True to include all the memory used by underlying parts that construct the pd.Series
 4176

这样我们才能根据对象的内存占用来查看实际的优化结果

slots

Python作为一种动态类型语言,在面向对象方面具有更大的灵活性。在运行时可以向Python类添加额外属性和方法的能力。

例如,下面的代码定义了一个名为Author的类。最初它有两个属性name和age。但是我们以后可以很容易地添加一个额外的job:

 class Author:
     def __init__(self, name, age):
         self.name = name
         self.age = age
 
 
 me = Author('Yang Zhou', 30)
 me.job = 'Software Engineer'
 print(me.job)
 # Software Engineer

但是这种灵活性在底层浪费了更多内存。

因为Python中每个类的实例都维护一个特殊的字典(dict)来存储实例变量。因为字典的底层基于哈希表的实现所以消耗了大量的内存。

在大多数情况下,我们不需要在运行时更改实例的变量或方法,并且__dict__不会(也不应该)在类定义后更改。所以Python为此提供了一个属性:slots

它通过指定类的所有有效属性的名称来作为白名单:

 class Author:
     __slots__ = ('name', 'age')
 
     def __init__(self, name, age):
         self.name = name
         self.age = age
 
 
 me = Author('Yang Zhou', 30)
 me.job = 'Software Engineer'
 print(me.job)
 # AttributeError: 'Author' object has no attribute 'job'

白名单只定义了两个有效的属性name和age。由于属性是固定的,Python不需要为它维护字典,只为__slots__中定义的属性分配必要的内存空间。

下面我们做一个简单的比较:

 import sys
 
 
 class Author:
     def __init__(self, name, age):
         self.name = name
         self.age = age
 
 
 class AuthorWithSlots:
     __slots__ = ['name', 'age']
 
     def __init__(self, name, age):
         self.name = name
         self.age = age
 
 
 # Creating instances
 me = Author('Yang', 30)
 me_with_slots = AuthorWithSlots('Yang', 30)
 
 # Comparing memory usage
 memory_without_slots = sys.getsizeof(me) + sys.getsizeof(me.__dict__)
 memory_with_slots = sys.getsizeof(me_with_slots)  # __slots__ classes don't have __dict__
 
 print(memory_without_slots, memory_with_slots)
 # 152 48
 print(me.__dict__)
 # {'name': 'Yang', 'age': 30}
 print(me_with_slots.__dict__)
 # AttributeError: 'AuthorWithSlots' object has no attribute '__dict__'

可以看到 152 和 48 明显节省了内存。

Generators

生成器是Python中列表的惰性求值版本。每当调用next()方法时生成一个项,而不是一次计算所有项。所以它们在处理大型数据集时非常节省内存。

 def number_generator():
     for i in range(100):
         yield i
 
 numbers = number_generator()
 print(numbers)
 # <generator object number_generator at 0x104a57e40>
 print(next(numbers))
 # 0
 print(next(numbers))
 # 1

上面的代码显示了一个编写和使用生成器的基本示例。关键字yield是生成器定义的核心。应用它意味着只有在调用next()方法时才会产生项i。

让我们比较一个生成器和一个列表,看看哪个更节省内存:

 mport sys
 
 numbers = []
 for i in range(100):
     numbers.append(i)
 
 def number_generator():
     for i in range(100):
         yield i
 
 numbers_generator = number_generator()
 print(sys.getsizeof(numbers_generator))
 # 112
 print(sys.getsizeof(numbers))
 # 920

可以看到使用生成器可以显著节省内存使用。如果我们将列表推导式的方括号转换成圆括号,它将成为生成器表达式。这是在Python中定义生成器的更简单的方法:

 import sys
 
 numbers = [i for i in range(100)]
 numbers_generator = (i for i in range(100))
 
 print(sys.getsizeof(numbers_generator))
 # 112
 print(sys.getsizeof(numbers))
 # 920

利用内存映射文件支持大文件处理

内存映射文件I/O,简称“mmap”,是一种操作系统级优化。

简单地说,当使用mmap技术对文件进行内存映射时,它直接在当前进程的虚拟内存空间中创建文件的映射,而不是将整个文件加载到内存中,这节省了大量内存。

Python已经提供了用于使用此技术的内置模块,因此我们可以轻松地利用它,而无需考虑操作系统级别的实现。

以下是如何在Python中使用mmap进行文件处理:

 import mmap
 
 
 with open('test.txt', "r+b") as f:
     # memory-map the file, size 0 means whole file
     with mmap.mmap(f.fileno(), 0) as mm:
         # read content via standard file methods
         print(mm.read())
         # read content via slice notation
         snippet = mm[0:10]
         print(snippet.decode('utf-8'))

Python使内存映射文件I/O技术的使用变得方便。我们所需要做的只是应用mmap.mmap()方法,然后使用标准文件方法甚至切片符号处理打开的对象。

选择适当的数据类型

开发人员应仔细而精确地选择数据类型。因为在某些情况下,使用一种数据类型比使用另一种数据类型更节省内存。

1、元组比列表更节省内存

元组是不可变的(在创建后不能更改),它允许Python在内存分配方面进行优化。列表是可变的,因此需要额外的空间来容纳潜在的修改。

 import sys
 
 my_tuple = (1, 2, 3, 4, 5)
 my_list = [1, 2, 3, 4, 5]
 
 print(sys.getsizeof(my_tuple))
 # 80
 print(sys.getsizeof(my_list)) 
 # 120

元组my_tuple比列表使用更少的内存,如果创建后不需要更改数据,我们应该选择元组而不是列表。

2、数组比列表更节省内存

Python中的数组要求元素具有相同的数据类型(例如,所有整数或所有浮点数),但列表可以存储不同类型的对象,这不可避免地需要更多的内存。如果列表的元素都是相同类型,使用数组会更节省内存:

 import sys
 import array
 
 my_list = [i for i in range(1000)]
 
 my_array = array.array('i', [i for i in range(1000)])
 
 print(sys.getsizeof(my_list))  
 # 8856
 print(sys.getsizeof(my_array)) 
 # 4064

另外:Python是数据科学的主导语言。有许多强大的第三方模块和工具提供更多的数据类型,如NumPy和Pandas。如果我们只需要一个简单的一维数字数组,而不需要NumPy提供的广泛功能,那么Python的内置数组是一个不错的选择。但当涉及到复杂的矩阵操作时,使用NumPy提供的数组是所有数据科学家的首选,也可能是最佳选择。

字符串驻留

看看下面的代码:

 >>> a = 'Y'*4096
 >>> b = 'Y'*4096
 >>> a is b
 True
 >>> c = 'Y'*4097
 >>> d = 'Y'*4097
 >>> c is d
 False

为什么a是b是真,而c是d是假呢?

这在Python中被称作字符串驻留(string interning).如果有几个值相同的小字符串,它们将被Python隐式地存储并在内存中并引用相同的对象。定义小字符串阈值数字是4096。

由于c和d的长度为4097,因此它们是内存中的两个对象而不是一个对象,不再隐式驻留字符串。所以当执行c = d时,我们得到一个False。

驻留是一种优化内存使用的强大技术。如果我们想要显式地使用它可以使用sys.intern()方法:

 >>> import sys
 >>> c = sys.intern('Y'*4097)
 >>> d = sys.intern('Y'*4097)
 >>> c is d
 True

https://avoid.overfit.cn/post/67b82ca0447e4ebf9dac35fa820156b7

作者:Yang Zhou文章来源地址https://www.toymoban.com/news/detail-799746.html

到了这里,关于提高代码效率的6个Python内存优化技巧的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 几种技巧让大模型(ChatGPT、文心一言)帮你提高写代码效率!

    自从大模型推出来之后,似乎没有什么工作是大模型不能做的。特别是在文本生成、文案写作、代码提示、代码生成、代码改错等方面都表现出不错的能力。下面我将介绍运用大模型写代码的几种方式,帮助程序员写出更好的代码!(大模型包括但不限于 ChatGPT、文心一言【

    2024年02月08日
    浏览(90)
  • 涨点技巧: 谷歌强势推出优化器Lion,引入到Yolov8,内存更小、效率更高,秒杀Adam(W)

    论文:https://arxiv.org/abs/2302.06675 代码:automl/lion at master · google/automl · GitHub 1

    2023年04月18日
    浏览(38)
  • (实用)如何在vscode设置自己的代码片段,提高开发效率

     项目背景 很多时候,我们新建vue文件的时,都需要把重复的代码结构重新输入或者copy过来,对开发效率照成影响。😫 可以通过键入 vue3 快速生成代码片段 构建效果 操作步骤 在vscode左下角,点击设置按钮,选择新建 用户代码片段 : 也可以在 文件 / 首选项 / 配置用

    2024年04月09日
    浏览(48)
  • 大型企业如何通过低代码平台提高开发效率和降低成本?

    云计算、大数据、人工智能、物联网风口之下,企业数字化转型如同被按下了快进键。为快速攻破转型路上的技术关,企业纷纷把目光投向了低代码开发平台,希望可以用最短的时间,开发出最适合企业发展的应用。 首先,我们要明确一个问题,那就是对于集团型企业来说,

    2024年02月06日
    浏览(73)
  • 助你加速开发效率!告别IDEA卡顿困扰的性能优化技巧

    在现代软件开发中,IDE(集成开发环境)是一个必不可少的工具。IntelliJ IDEA是一个广受欢迎的IDE,但有时候IDE的性能可能会受到影响,导致开发人员的工作效率降低。本文将介绍一些可以提高IDE性能的技巧,帮助开发人员消除卡顿困扰。 优化IDE的配置 在IDEA中,可以通过修改

    2024年01月25日
    浏览(61)
  • chatgpt赋能python:Python动态内存分配:如何优化你的代码

    在编写Python代码时,你可能已经注意到内存使用方面的一些问题。Python动态内存分配是一个重要的话题,它涉及到Python程序如何在运行时使用内存。本文将向您介绍Python动态内存分配的基本概念和如何优化您的代码以节省内存。 Python是一种解释型语言,它在运行时使用动态内

    2024年02月07日
    浏览(44)
  • 低代码制造ERP管理系统:降低开发成本,提高生产效率

    随着制造业的快速发展,ERP管理系统成为了现代制造业中不可或缺的一部分。ERP管理系统可以帮助企业更好地管理生产流程、库存和供应链等方面,从而提高企业的生产效率和竞争力。然而,传统的ERP管理系统往往需要大量的编程工作和长周期的开发过程,这对于一些中小型

    2024年02月12日
    浏览(58)
  • 涨点技巧: 谷歌强势推出优化器Lion,引入到Yolov5/Yolov7,内存更小、效率更高,秒杀Adam(W)

    论文:https://arxiv.org/abs/2302.06675 代码:automl/lion at master · google/automl · GitHub 1)与 AdamW 和各种自适应优化器需要同时保存一阶和二阶矩相比,Lion 只需要动量,将额外的内存占用减半; 2)由于 Lion 的简单性,Lion 在我们的实验中具有更快的运行时间(step/s),通常比 AdamW 和

    2024年02月16日
    浏览(46)
  • 低代码开发:是提高效率的美味佳肴还是无法满足深度需求的垃圾食品?

    有志者自有千计万计,无志者只感千难万难。 随着技术的不断发展,软件开发方式也在不断地演变。其中,低代码开发作为一种快速开发的方式,受到了越来越多的关注。有人认为低代码开发是美味的膳食,让开发变得高效而满足,但也有人质疑其缺乏定制性与深度,认为其

    2024年02月05日
    浏览(42)
  • 提高C++运行效率技巧

    在C++中,通过查表(Look-Up Table, LUT)来计算三角函数的数值是一种节省时间的方法,尤其是在需要快速计算且对精度要求不是特别高的情况下。这种方法通常用于嵌入式系统或实时应用,因为这些场景中对计算速度有较高要求,而硬件资源可能有限。 查表法的基本思想是预先

    2024年02月20日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包