网站首页 > 技术文章 正文
Python缓存整数
整数,在Python中,不是以传统的2、4或8字节实现,而是将其实现为以230为基数的整数数组,因此Python支持超长整数。又因为整数没有明确的长度限制,所以在Python中使用整数非常方便,即使我们对很长的整数进行运算,也不必担心整数溢出。但这种便利的代价是资源分配较高,同时常用运算(例如加法,乘法,除法)的执行效率较低。
Python中的每个整数都实现为一个C语言结构体, 如下所示。
可以观察到,与其它的较长整数相比,-5至256范围内的较小整数使用非常频繁,为了性能上优势,Python在初始化过程中预先分配了该范围内的整数对象,并使它们成为单例,因此每次在使用较小整数时, 使用的是相应单例的引用,而不是重新分配新的整数对象。
下面是Python官方文档中关于整数预分配的相关内容:
“当前的整数实现会为-5至256之间的所有整数维护一个整数对象数组,当你创建该范围内的整数时, 你实际得到的是现有整数对象的引用。”
在CPython的源码中,可以在IS_SMALL_INT宏和longobject.c模块中的get_small_int函数中跟踪此优化。因此,Python为常用整数节省了大量的空间和计算量。
验证这些较小整数对象是否是单例
对于CPython, 内置的id函数返回对象的内存地址。这意味着,如果较小整数确实是单例,对于相同较小整数值的两个实例, id函数应该返回相同的内存地址,而对于较长整数的多个实例应返回不同的内存地址,这确实是我们观察到的:
较小整数的这种单例现象也可以在计算过程中观察到。在下面的示例中,通过对三个不同的整数2、4和10进行两次运算,我们得到了相同的目标值6,并且在这两种情况下,我们看到id函数返回了相同的内存地址:
验证这些较小整数对象是否经常被引用
我们已经确定,在Python中使用较小整数,是通过引用它们相应的单例对象来实现,而无需每次都重新分配内存创建整数对象。现在我们需要验证以下假设:“Python初始化的时候, 通过这些单例对象,确实节省了大量的内存分配操作”;我们可以通过检查每个整数值的引用计数来验证上面的假设。
引用计数
引用计数,维护着同一对象在不同位置被引用的数目,对象每次被引用时,其属性ob_refcnt(对象引用计数)会增加1,对象引用被取消时, ob_refcnt会减少1,当引用计数为0时,该对象将会被垃圾回收。
我们使用sys模块中的getrefcount函数来获取一个对象的当前引用计数;
当对-5至300之间的所有整数执行此操作时,我们得到以下分布:
上图显示,较小整数的引用计数很高,表明使用率很高,同时引用计数随着这些整数值的增加而降低;这证实了, 在Python初始化期间, 相比于较长整数,较小整数被更多对象引用。
整数值0被引用的最多——359次,沿着分布图的长尾,可以看到引用计数的峰值为2的幂次,如32, 64, 128和256。Python在初始化的过程中本身需要较小整数值,因此通过单例模式节省了大约1993次的较小整数对象的创建。
这些引用计数是在新打开的Python进程计算的,这意味着,Python初始化时,需要使用一些整数值进行计算,并通过使用较小整数值的单例来加速计算。
在通常的编程实践中, 相比于较长整数,较小整数的使用更频繁,并且这些整数值的单例实例可以为Python节省大量的计算量和内存分配操作。
参考:
Python Object Types and Reference Counts
How python implements super-long integers
Why Python is Slow: Looking Under the Hood
英文原文:https://arpitbhayani.me/blogs/python-caches-integers
译者:张恒源
- 上一篇: 老鸟进阶必备技能,看懂显示器参数
- 下一篇: 你需要了解的最重要的Python概念
猜你喜欢
- 2024-11-20 Python基础编程——算术运算
- 2024-11-20 Python字符串方法之-字符串填充
- 2024-11-20 Python第14题:最长公共前缀【leetcode】
- 2024-11-20 从 0 到 1:构建强大且易用的规则引擎
- 2024-11-20 分享3个干货满满的Python实战项目,点赞收藏
- 2024-11-20 python笔记8:静静一起来学习-字符串相关方法
- 2024-11-20 零基础Python完全自学教程14:Python中的序列知识详解
- 2024-11-20 你需要了解的最重要的Python概念
- 2024-11-20 老鸟进阶必备技能,看懂显示器参数
- 2024-11-20 Python案例:使用for…in循环完成内容长度的计算
- 最近发表
-
- 如何在 Linux 上安装 Java_怎么在linux中安装jdk
- Linux中tar命令打包路径相关问题_linux怎么用tar打包一个目录
- 常用linux系统常用扫描命令汇总_常用linux系统常用扫描命令汇总表
- VM下linux虚拟机新建过程(有图)_linux虚拟机创建新用户命令
- 系统小技巧:迁移通过Wubi方式安装的Ubuntu系统
- 文件系统(八):Linux JFFS2文件系统工作原理、优势与局限
- 如何利用ftrace精确跟踪特定进程调度信息
- prometheus网络监控之fping-exporter
- hyper linux的实操步骤,hyper-v批量管理工具的使用指南
- 2021年,运维工程师笔试真题(二)(附带答案)
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)