龙空技术网

Python的数据缓存机制探究

玩转Python 432

前言:

现在姐妹们对“python清理缓存”都比较注重,咱们都需要了解一些“python清理缓存”的相关文章。那么小编在网络上搜集了一些对于“python清理缓存””的相关文章,希望姐妹们能喜欢,兄弟们快快来学习一下吧!

在学习Python过程中,我们可能会偶尔会遇见下面的这些情况:

说明:id()函数用来获取某个变量/数据对象的内存地址;is操作符用来判断两个变量/数据对象是否指向同一个内存地址。

(E1)在Python的IDLE交互式模式下,当两个变量a和b同时赋值为256时,它们的内存地址是一致的,因此用a is b进行判断时结果为True,但当它们同时赋值为257时,内存地址却不一样,a is b的结果为False。

(E2)在Python的IDLE文件模式下,当a和b同时赋值为257时,它们的内存地址却是一样的。

(E3)在Python的IDLE文件模式下,分别使用直接赋值和表达式赋值两种方式对a和b赋值为257时,发现:直接赋值的内存地址是一样的,而表达式赋值方式的地址是不一样的。

(E4)在Python中,对两个变量a和b同时赋值为空元组时,它们的内存地址是一样的,当它们同时赋值为空列表时,内存地址却不一样。

(E5)在Python中,当两个变量a和b同时赋值为不同的列表时,他们的内存地址肯定是不一样,但它们中相同元素的地址可能是一样的。

......

以上所列情况仅仅是个例,并不能从中总结出比较完备的规律。在好奇心的驱使下,作者大量尝试了各种数据类型的各种情况,并查阅了相关资料,才明白这是Python的缓存机制在作怪。什么是Python的缓存机制呢?

一、什么是Python缓存机制

大家都知道现实生活中很多场景都符合二八定律,在程序中也是一样,经常被使用的数据对象可能会占据所有数据对象使用频率的80%,因此为了优化程序,提高程序的执行效率,Python解释器会将常用数据对象放在缓存中,一旦使用时,将数据对象的引用传递过去即可。

Python缓冲机制是为提高程序执行的效率服务的,实际上就是在Python解释器启动时从内存空间中开辟出一小部分,用来存储高频使用的对象,这样可以大大减少高频使用的数据对象创建时申请内存和销毁时撤销内存的开销。

那么接下来的问题来了,什么样的数据类型会使用缓存呢?整数?浮点数?字符串?列表?

二、什么数据类型会使用缓存?

在Python中,数据类型可以划分为基本数据类型和组合数据类型,基本数据类型主要包括:整数、浮点数、复数、布尔、字符串,组合数据类型主要包括:元组、列表、集合、字典。

根据数据是否可变,数据类型又可以分为:可变类型和不可变类型,可变类型包括:列表、集合、字典,上述其他的都属于不可变类型。

可变类型意味着在程序执行过程中可能会随时发生变化,因此它就失去了缓存的意义,所以在Python中使用缓存的规律是:

(1)不可变数据类型可能会使用缓存,具体是否使用缓存会依赖于数据类型和数据本身的具体情况,在第三节中会对每种数据类型进行详细讨论。

(2)可变数据类型肯定不使用缓存,但可变数据类型里面的元素如果是不可变类型的话,则内部元素可能使用缓存(例如上面的E5的例子)。从下面的代码示例可以看出,当数据类型为列表、字典或集合时,无论它们是同为空或者有相同的数据,它们都占用着不同的地址空间。

三、不可变数据类型的缓存机制

从E1的示例可以看出,交互式模式下256是使用了缓存,但257却没有,然而通过E2可以看出,在文件式模式下,256和257都使用了缓存。但从E3可以看出如果257是由表达式计算得到的话,那么它将不使用缓存。

通过以上的现象并经过作者大量的尝试和查阅资料,作者认为:Python中缓存分为固定缓存和运行时缓存(作者自行总结起的名字,不喜勿喷,如果有更权威的说法还望留言告知)。固定缓存是在解释器启动时就创建的,比如整数的[-5, 256]、None、True、False。运行时缓存是指在程序执行过程中,解释器为了优化程序数据对象的创建而设定的缓存,比如字符串、[-5, 256]以外的整数等。

3.1 整数

对于整数,有如下规律:

(1)Python中整数[-5, 256]为固定缓存,在解释器启动时就会创建,程序中只要是使用到该范围内的数字,不管是直接赋值还是表达式计算得到的,都会使用固定缓存中的数据。

打印-10到0的数据内存地址可以看到,[-10,-6]和[-5,0]使用的地址空间是不一样的,这也印证了[-5, 256]是使用固定区域缓存的这一说法。同时还可以发现[-10,-6]在输出时只使用了两个内存地址,在交替使用,这是因为在示例中,循环变量i每次循环都会变化一次,输出完后i就不再指向该数据,而指向了i+1,i就会很快被Python垃圾回收机制自动收回。

(2)小于-5的整数永远不会使用缓存,不论在交互式环境下还是在文件式环境下。

(3)对于大于256的整数,如果是由表达式计算得到的相同数值,肯定不会使用缓存。如果是直接赋值的情况下,在某些情况下可能会使用运行时缓存,分为两种情况:

a、在交互式模式下,如果两个变量不是同时赋值为同一个大于256的整数,那么它们将不使用运行时缓存,如果两个变量同步赋值或者在同一个代码块中,这时会使用运行时缓存。

b、在文件式模式下,如果两个变量同时属于局部变量或者同时属于全局变量,那么它们可以使用运行时缓存,如果它们一个是全局变量,一个是局部变量,就不会使用运行时缓存。

3.2 浮点数

对于浮点数,在文件式模式下,小于0.0的浮点数不会使用运行时缓存,只有>=0.0的浮点数才会使用运行时缓存。在交互式模式下时,除非同时赋值或者在同一个代码块下(>=0.0的浮点数才会使用运行时缓存),否则任何浮点数都不会使用运行时缓存。

交互式模式下示例:

3.3 字符串

对于字符串,是否使用运行时缓存存在以下规律(在文件式模式下):

(1)直接赋值的字符串,无论多长,是否包含特殊字符(#.-@等),都会使用运行时缓存。

(2)通过表达式计算得到字符串:如果只包含字母(a-z,A-Z)和数字(0-9),并且最终的长度不超过20的情况下,也会使用运行时缓存。一旦长度超过20,将不使用缓存;如果最终字符串中包含特殊字符(#.-@等),不论长度多长,将不使用缓存。

在交互式模式下(同时赋值/同一代码块除外),当字符串长度大于1时,只要字符串中有有特殊字符,就不会使用缓存。当字符串长度为1时,任何字符的字符串都会使用缓存。

3.4 True、False、None

任何情况下都使用固定缓存

3.5 元组

由于元组是可以嵌套不可变类型,因此Python中对于非空元组不使用缓存,但对空的元组使用运行时缓存。

3.6 复数

这个类型作者从没用过,就不做解读了,欢迎好事者补充。

以上是作者对于Python缓存机制的总结,测试环境是Python3.5,不一定完整,也可能存在错误。欢迎大家进行讨论,并提出宝贵意见,喜欢的朋友也可以关注本头条号,【玩转Python】将持续为大家提供优质的技术内容。

标签: #python清理缓存 #python缓存重用机制