c++ list 修改_Cpython源码阅读17-list自动扩容原理
list是python的高级特性,今天我们来学习一下list的底层结构。list(列表)就像一个大仓库,里边什么都可以放,学习过底层结构之后,就会认同这句话。python中一切皆对象,先点出来,列表中存放的元素其实是泛型指针PyObject*,所以什么都可以放。根据我们列表的直观感受,每个列表中的元素个数可能会不一样,所以列表示一个变长对象;列表中的元素可以进行添加、删除、修改等操作,所以列表是一个可变对象。
![](/assets/blank.gif)
列表常用的操作
其中,需要注意的是性能问题,pop从尾部弹出一个元素,时间复杂度为O(1);从头部弹出一个元素,后面的元素都需要移动,时间复杂度为O(n)。
先看一下List 对象的底层结构,PyListObject,通过前面的学习,这个很简单了。
typedef struct { PyObject_VAR_HEAD//变长对象公共头部信息 PyObject **ob_item;//二级指针,指向一个PyObject*类型的指针数组, //这个指针数组保存的是对象指针 Py_ssize_t allocated;//列表底层使用C数组,列表的容量,非实际大小} PyListObject;
通过前面的学习,我们知道一个变长对象是通过ob_size字段来指示对象的实际大小的。列表多了一个字段allocated来表示容量,之所以要有容量这个概念,是因为列表需要动态添加元素。在动态添加元素时,如果每添加一个元素,就申请一次数组,将所有元素都拷贝一次,性能太低。加了容量这个字段,添加新元素,发现底层数组已满,会将底层数组申请的长一些,添加元素的时候不用每次都申请新的数组。
![](/assets/blank.gif)
PyListObject示意图
可以看出,此时列表中有两个元素,但是列表的容量是6。我们再append两个元素,如下示意图,可以看出容量最大为6,不需要重新申请数组。
![](/assets/blank.gif)
尾部添加元素示意图
在此基础上再增加三个元素在尾部,实际元素个数为7,容量为6,需要扩容,看一下示意图:原来的容量为6,元素个数为4,append3个元素后,假设容量为10,元素个数为7。扩容的时候把容量申请的比实际元素大一些。然后将原来数组中的PyObject*按照顺序依次拷贝到新的数组里边,再将ob_item指向新的数组,再将ob_size加3。这就是列表扩容的过程。看一下实际源码
![](/assets/blank.gif)
list对象扩容底层示意图
//代码位置cpython-masterObjectslistobject.clist_resize(PyListObject *self, Py_ssize_t newsize)//参数self就是列表,newsize是元素添加或者减少之后的ob_size{ PyObject **items;//这个二级指针,用来指向指针数组 size_t new_allocated, num_allocated_bytes;//新的容量和对应的内存大小 Py_ssize_t allocated = self->allocated;//获取原来的容量 //如果newsize达到了总量的一半,但是还没有超过容量,说明newsize和容量的匹配的,不会扩容 if (allocated >= newsize && newsize >= (allocated >> 1)) { assert(self->ob_item != NULL || newsize == 0); Py_SET_SIZE(self, newsize); return 0; }//走到这里说明容量和ob_size不匹配,要进行扩容或者缩容 //新申请的底层数组的容量由下边的公式决定 new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3; //也不能过度分配 if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize)) new_allocated = ((size_t)newsize + 3) & ~(size_t)3; //如果newsize为0,那么容量也会清空 if (newsize == 0) new_allocated = 0; //数组中存放的是PyObject*,所以要计算内存 num_allocated_bytes = new_allocated * sizeof(PyObject *); //申请相应大小的内存,赋值给指针items items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes); //申请失败 if (items == NULL) { PyErr_NoMemory(); return -1; } //指向新的数组,实现扩容或者缩容 self->ob_item = items; //元素的实际个数 Py_SET_SIZE(self, newsize); //原来容量的大小设置为新的大小 self->allocated = new_allocated; return 0;}
new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3;
从这个公式的注释得到扩容的规律:The growth pattern is: 0, 4, 8, 16, 24, 32, 40, 52, 64, 76, ...
c++ list 修改_Cpython源码阅读17-list自动扩容原理相关推荐
- pytorch load state dict_pytorch源码阅读(二)optimizer原理
pytorch包含多种优化算法用于网络参数的更新,比如常用的SGD.Adam.LBFGS以及RMSProp等.使用中可以发现各种优化算法的使用方式几乎相同,是因为父类optimizer[1]定义了各个 ...
- 【Spring Boot实战】源码解析Spring Boot自动配置原理
一.简介 Spring致力于让Java开发更简单,SpringBoot致力于让使用Spring进行Java开发更简单,SpringCloud致力于基于SpringBoot构建微服务生态圈,让微服务开发 ...
- 17 任务调度相关类综述——Live555源码阅读(一)任务调度相关类
这是Live555源码阅读的第二部分,包括了任务调度相关的三个类.任务调度是Live555源码中很重要的部分. 本文由乌合之众 lym瞎编,欢迎转载 http://www.cnblogs.com/ol ...
- spring源码阅读(3)-- 容器启动之BeanFactoryPostProcessor
接着上文<spring源码阅读(2)-- 容器启动之加载BeanDefinition>,当spring加载完所有BeanDefinition时,并不会马上去创建bean,而是先配置bean ...
- NJ4X源码阅读分析笔记系列(三)—— nj4x-ts深入分析
NJ4X源码阅读分析笔记系列(三)-- nj4x-ts深入分析 一.系统的工作流程图(模块级) 其工作流程如下(以行情获取为例): 应用端向Application Server发起连接 应用服务器调用 ...
- gh-ost大表DDL工具源码阅读
gh-ost大表DDL工具源码阅读 最终目的 开发环境与测试数据库准备 一个简单的ddl案例 debug分析程序执行过程 vscode debug配置 变量介绍 核心处理逻辑 分析我的需求 最终目的 ...
- Golang流媒体实战之五:lal推流服务源码阅读
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos <Golang流媒体实战>系列的链接 体验 ...
- Mybatis 源码阅读环境搭建
Mybatis源码阅读环境搭建 前言 一.下载mybatis的源码 二.编译源码 三.创建测试项目 前言 mybatis源码阅读环境搭建还是比较简单的,接下来我们讲解一下如何搭建该源码阅读环境 ...
- Spark源码学习之IDEA源码阅读环境搭建
软件准备 (1)Java 1.8 (2)Scala 2.11.12(需要在IDEA中安装) (3)Maven 3.8.2(需要在IDEA中配置) (4)Git 2.33 以上软件需要安装好,并进行环境 ...
最新文章
- js 获取input type=file 文件,并且上传
- 人生第一次:领年终,拿股票!
- [转]40种网页常用小技巧----Ajax中国
- typora最好用的主题_谁是我心中最好的写作工具?
- 计算机里的文件弄不到桌面怎么办,笔记本电脑桌面上的文件夹不见了怎么办
- android构建过程
- 《网络安全——应用技术与工程实践》
- leetcode - Missing Ranges
- android 应用退到后台,类似最小化
- CRM One Order search max hit实现原理讨论
- stdin,stdout,stderr
- HTML5与HTML4区别
- vpp之node节点分析二: qs类型
- 微型计算机原理王忠民PPT,微型计算机原理4 王忠民著.ppt
- DX11 游戏开发笔记 (一) 资源介绍
- ios 图表_在ios应用中实现蜘蛛网图表
- 青春魅族为何一幅“龙钟老态”?
- 使用CDN后网页无法访问怎么解决
- 论文阅读利器——划词翻译插件(桌面与浏览器)
- jquery 学习笔记及小练习
热门文章
- MySql数据库连接池
- 体验XHProf(linux版本)
- Bug反思:减少笔误
- dubbo web工程示例_带有Dubbo的Spring Cloud Alibaba
- java中自造类是什么意思_JAVA问题,什么时候需要,Class类型的?
- tcpip c语言程序设计,TCP 服务端和客户端程序设计(C)
- android 微信登录点击没翻译,[android] 微信登录,没有唤起微信,直接返回ERR_AUTH_DENIED...
- c语言基础傅里叶变换,急求:C语言如何实现快速傅里叶变换
- 【Nginx】截取URL中某个参数Parameter
- MySQL 错误 #1113