当前位置:首页 » 硬盘大全 » python缓存设置
扩展阅读
webinf下怎么引入js 2023-08-31 21:54:13
堡垒机怎么打开web 2023-08-31 21:54:11

python缓存设置

发布时间: 2022-12-19 15:45:19

㈠ 如何在python中使用时间限制进行缓存

可以试试装饰器

defcache(fn=None,time_to_live=3600*24):#oneDAYdefault(orwhatever)
ifnotfn:returnfunctools.partial(cache,time_to_live=time_to_live)
my_cache={}
def_inner_fn(*args,**kwargs)
kws=sorted(kwargs.items())#inpython3.6+youdontneedsorted
key=tuple(args)+tuple(kw)
ifkeynotinmy_cacheortime.time()>my_cache[key]['expires']:
my_cache[key]={"value":fn(*args,**kwargs),"expires":time.time()+time_to_live}
returnmy_cache[key]
return__inner_fn

@cache(time_to_live=3600)#anhour
defmy_sqrt(x):
returnx**0.5@cache(time_to_live=60*30)#30mins
defget_new_emails():
returnmy_stmp.get_email_count()

㈡ python 将计算结果保留到缓存中

定义一个延迟属性的一种高效方法是通过使用一个描述器类,如下所示:

<pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; display: block; overflow: auto; line-height: 1.4;">class lazyproperty:
def init (self, func):
self.func = func

</pre>

你需要像下面这样在一个类中使用它:

<pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; display: block; overflow: auto; line-height: 1.4;">import math

class Circle:
def init (self, radius):
self.radius = radius

</pre>

下面在一个交互环境中演示它的使用:

<pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; display: block; overflow: auto; line-height: 1.4;">>>> c = Circle(4.0)

</pre>

仔细观察你会发现消息 Computing area 和 Computing perimeter 仅仅出现一次。

很多时候,构造一个延迟计算属性的主要目的是为了提升性能。 例如,你可以避免计算这些属性值,除非你真的需要它们。 这里演示的方案就是用来实现这样的效果的, 只不过它是通过以非常高效的方式使用描述器的一个精妙特性来达到这种效果的。

正如在其他小节(如8.9小节)所讲的那样,当一个描述器被放入一个类的定义时, 每次访问属性时它的 __get__() 、 __set__() 和 __delete__() 方法就会被触发。 不过,如果一个描述器仅仅只定义了一个 __get__() 方法的话,它比通常的具有更弱的绑定。 特别地,只有当被访问属性不在实例底层的字典中时 __get__() 方法才会被触发。

lazyproperty 类利用这一点,使用 __get__() 方法在实例中存储计算出来的值, 这个实例使用相同的名字作为它的property。 这样一来,结果值被存储在实例字典中并且以后就不需要再去计算这个property了。 你可以尝试更深入的例子来观察结果:

<pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; display: block; overflow: auto; line-height: 1.4;">>>> c = Circle(4.0)

</pre>

这种方案有一个小缺陷就是计算出的值被创建后是可以被修改的。例如:

<pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; display: block; overflow: auto; line-height: 1.4;">>>> c.area
Computing area
50.26548245743669

</pre>

如果你担心这个问题,那么可以使用一种稍微没那么高效的实现,就像下面这样:

<pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; display: block; overflow: auto; line-height: 1.4;">def lazyproperty(func):
name = ' lazy ' + func. name
@property
def lazy(self):
if hasattr(self, name):
return getattr(self, name)
else:
value = func(self)
setattr(self, name, value)
return value
return lazy
</pre>

如果你使用这个版本,就会发现现在修改操作已经不被允许了:

<pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; display: block; overflow: auto; line-height: 1.4;">>>> c = Circle(4.0)

㈢ 软件开发模版缓存具体步骤怎么操作的呢

模板缓存就是把模版内容缓存到指定位置,只要涉及模版都可以设置缓存,

下面以py程序为例:
1.1 在导入搜索期间首先会被检查的地方是 sys.moles。 这个映射起到缓存之前导入的所有模块的作用(包括其中间路径)。 因此如果之前导入过 foo.bar.baz,则 sys.moles 将包含 foo, foo.bar 和 foo.bar.baz 条目。 每个键的值就是相应的模块对象。
在导入期间,会在 sys.moles 查找模块名称,如存在则其关联的值就是需要导入的模块,导入过程完成。 然而,如果值为 None,则会引发 MoleNotFoundError。 如果找不到指定模块名称,Python 将继续搜索该模块。
1.2 sys.moles 是可写的。删除键可能不会破坏关联的模块(因为其他模块可能会保留对它的引用),但它会使命名模块的缓存条目无效,导致 Python 在下次导入时重新搜索命名模块。键也可以赋值为 None ,强制下一次导入模块导致 MoleNotFoundError 。
但是要小心,因为如果你还保有对某个模块对象的引用,同时停用其在 sys.moles 中的缓存条目,然后又再次导入该名称的模块,则前后两个模块对象将 不是 同一个。 相反地,

1.3 importlib.reload() 将重用 同一个 模块对象,并简单地通过重新运行模块的代码来重新初始化模块内容。

1.1 在导入搜索期间首先会被检查的地方是 sys.moles。 这个映射起到缓存之前导入的所有模块的作用(包括其中间路径)。 因此如果之前导入过 foo.bar.baz,则 sys.moles 将包含 foo, foo.bar 和 foo.bar.baz 条目。 每个键的值就是相应的模块对象。
在导入期间,会在 sys.moles 查找模块名称,如存在则其关联的值就是需要导入的模块,导入过程完成。 然而,如果值为 None,则会引发 MoleNotFoundError。 如果找不到指定模块名称,Python 将继续搜索该模块。
1.2 sys.moles 是可写的。删除键可能不会破坏关联的模块(因为其他模块可能会保留对它的引用),但它会使命名模块的缓存条目无效,导致 Python 在下次导入时重新搜索命名模块。键也可以赋值为 None ,强制下一次导入模块导致 MoleNotFoundError 。
但是要小心,因为如果你还保有对某个模块对象的引用,同时停用其在 sys.moles 中的缓存条目,然后又再次导入该名称的模块,则前后两个模块对象将 不是 同一个。 相反地,

1.3 importlib.reload() 将重用 同一个 模块对象,并简单地通过重新运行模块的代码来重新初始化模块内容。

㈣ Python 的内存管理机制

Python采用自动内存管理,即Python会自动进行垃圾回收,不需要像C、C++语言一样需要程序员手动释放内存,手动释放可以做到实时性,但是存在内存泄露、空指针等风险。

Python自动垃圾回收也有自己的优点和缺点:优点:

缺点:

Python的垃圾回收机制采用 以引用计数法为主,分代回收为辅 的策略。

先聊引用计数法,Python中每个对象都有一个核心的结构体,如下

一个对象被创建时,引用计数值为1,当一个变量引用一个对象时,该对象的引用计数ob_refcnt就加一,当一个变量不再引用一个对象时,该对象的引用计数ob_refcnt就减一,Python判断是否回收一个对象,会将该对象的引用计数值ob_refcnt减一判断结果是否等于0,如果等于0就回收,如果不等于0就不回收,如下:

一个对象在以下三种情况下引用计数会增加:

一个对象在以下三种情况引用计数会减少:

验证案例:

运行结果:

事实上,关于垃圾回收的测试,最好在终端环境下测试,比如整数257,它在PyCharm中用下面的测试代码打印出来的结果是4,而如果在终端环境下打印出来的结果是2。这是因为终端代表的是原始的Python环境,而PyCharm等IDE做了一些特殊处理,在Python原始环境中,整数缓存的范围是在 [-5, 256] 的双闭合区间内,而PyCharm做了特殊处理之后,PyCharm整数缓存的范围变成了 [-5, 无穷大],但我们必须以终端的测试结果为主,因为它代表的是原始的Python环境,并且代码最终也都是要发布到终端运行的。

好,那么回到终端,我们来看两种特殊情况

前面学习过了,整数缓存的范围是在 [-5, 256] 之间,这些整数对象在程序加载完全就已经驻留在内存之中,并且直到程序结束退出才会释放占有的内存,测试案例如下:

如果字符串的内容只由字母、数字、下划线构成,那么它只会创建一个对象驻留在内存中,否则,每创建一次都是一个新的对象。

引用计数法有缺陷,它无法解决循环引用问题,即A对象引用了B对象,B对象又引用了A对象,这种情况下,A、B两个对象都无法通过引用计数法来进行回收,有一种解决方法是程序运行结束退出时进行回收,代码如下:

前面讲过,Python垃圾回收机制的策略是 以引用计数法为主,以分代回收为辅 。分代回收就是为了解决循环引用问题的。

Python采用分代来管理对象的生命周期:第0代、第1代、第2代,当一个对象被创建时,会被分配到第一代,默认情况下,当第0代的对象达到700个时,就会对处于第0代的对象进行检测和回收,将存在循环引用的对象释放内存,经过垃圾回收后,第0代中存活的对象会被分配为第1代,同样,当第1代的对象个数达到10个时,也会对第1代的对象进行检测和回收,将存在循环引用的对象释放内存,经过垃圾回收后,第1代中存活的对象会被分配为第2代,同样,当第二代的对象个数达到10个时,也会对第2代的对象进行检测和回收,将存在循环引用的对象释放内存。Python就是通过这样一种策略来解决对象之间的循环引用问题的。

测试案例:

运行结果:

如上面的运行结果,当第一代中对象的个数达到699个即将突破临界值700时(在打印699之前就已经回收了,所以看不到698和699)进行了垃圾回收,回收掉了循环引用的对象。

第一代、第二代、第三代分代回收都是有临界值的,这个临界值可以通过调用 gc.get_threshold 方法查看,如下:

当然,如果对默认临界值不满意,也可以调用 gc.set_threshold 方法来自定义临界值,如下:

最后,简单列出两个gc的其它方法,了解一下,但禁止在程序代码中使用

以上就是对Python垃圾回收的简单介绍,当然,深入研究肯定不止这些内容,目前,了解到这个程度也足够了。

㈤ python的内存管理机制

论坛

活动

招聘

专题

打开CSDN APP
Copyright © 1999-2020, CSDN.NET, All Rights Reserved

登录

XCCS_澍
关注
Python 的内存管理机制及调优手段? 原创
2018-08-05 06:50:53

XCCS_澍

码龄7年

关注
内存管理机制:引用计数、垃圾回收、内存池。
一、引用计数:
    引用计数是一种非常高效的内存管理手段, 当一个 Python 对象被引用时其引用计数增加 1, 当其不再被一个变量引用时则计数减 1. 当引用计数等于 0 时对象被删除。
二、垃圾回收 :
1. 引用计数
      引用计数也是一种垃圾收集机制,而且也是一种最直观,最简单的垃圾收集技术。当 Python 的某个对象的引用计数降为 0 时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了。比如某个新建对象,它被分配给某个引用,对象的引用计数变为 1。如果引用被删除,对象的引用计数为 0,那么该对象就可以被垃圾回收。不过如果出现循环引用的话,引用计数机制就不再起有效的作用了
2. 标记清除
     如果两个对象的引用计数都为 1,但是仅仅存在他们之间的循环引用,那么这两个对象都是需要被回收的,也就是说,它们的引用计数虽然表现为非 0,但实际上有效的引用计数为 0。所以先将循环引用摘掉,就会得出这两个对象的有效计数。
3. 分代回收
     从前面“标记-清除”这样的垃圾收集机制来看,这种垃圾收集机制所带来的额外操作实际上与系统中总的内存块的数量是相关的,当需要回收的内存块越多时,垃圾检测带来的额外操作就越多,而垃圾回收带来的额外操作就越少;反之,当需回收的内存块越少时,垃圾检测就将比垃圾回收带来更少的额外操作。

㈥ Python内存驻留机制

字符串驻留机制在许多面向对象编程语言中都支持,比如Java、python、Ruby、PHP等,它是一种数据缓存机制,对不可变数据类型使用同一个内存地址,有效的节省了空间,本文主要介绍Python的内存驻留机制。

字符串驻留就是每个字符串只有一个副本,多个对象共享该副本,驻留只针对不可变数据类型,比如字符串,布尔值,数字等。在这些固定数据类型处理中,使用驻留可以有效节省时间和空间,当然在驻留池中创建或者插入新的内容会消耗一定的时间。

下面举例介绍python中的驻留机制。

在Python对象及内存管理机制一文中介绍了python的参数传递以及以及内存管理机制,来看下面一段代码:

知道结果是什么吗?下面是执行结果:

l1和l2内容相同,却指向了不同的内存地址,l2和l3之间使用等号赋值,所以指向了同一个对象。因为列表是可变对象,每创建一个列表,都会重新分配内存,列表对象是没有“内存驻留”机制的。下面来看不可变数据类型的驻留机制。

Jupyter或者控制台交互环境 中执行下面代码:

执行结果:

可以发现a1和b1指向了不同的地址,a2和b2指向了相同的地址,这是为什么呢?

因为启动时,Python 将一个 -5~256 之间整数列表预加载(缓存)到内存中,我们在这个范围内创建一个整数对象时,python会自动引用缓存的对象,不会创建新的整数对象。

浮点型不支持:

如果上面的代码在非交互环境,也就是将代码作为python脚本运行的结果是什么呢?(运行环境为python3.7)

全为True,没有明确的限定临界值,都进行了驻留操作。这是因为使用不同的环境时,代码的优化方式不同。

Jupyter或者控制台交互环境 中:

满足标识符命名规范的字符:

结果:

乘法获取字符串(运行环境为python3.7)

结果:

在非交互环境中:

注意: 字符串是在编译时进行驻留 ,也就是说,如果字符串的值不能在编译时进行计算,将不会驻留。比如下面的例子:

在交互环境执行结果如下:

都指向不同的内存。

python 3.7 非交互环境执行结果:

发现d和e指向不同的内存,因为d和e不是在编译时计算的,而是在运行时计算的。前面的 a = 'aa'*50 是在编译时计算的。

除了上面介绍的python默认的驻留外,可以使用sys模块中的intern()函数来指定驻留内容

结果:

使用intern()后,都指向了相同的地址。

本文主要介绍了python的内存驻留,内存驻留是python优化的一种策略,注意不同运行环境下优化策略不一样,不同的python版本也不相同。注意字符串是在编译时进行驻留。

--THE END--

㈦ python如何进行内存管理

Python的内存管理主要有三种机制:引用计数机制,垃圾回收机制和内存池机制。
引用计数机制
简介
python内部使用引用计数,来保持追踪内存中的对象,Python内部记录了对象有多少个引用,即引用计数,当对象被创建时就创建了一个引用计数,当对象不再需要时,这个对象的引用计数为0时,它被垃圾回收。
特性
1.当给一个对象分配一个新名称或者将一个对象放入一个容器(列表、元组或字典)时,该对象的引用计数都会增加。
2.当使用del对对象显示销毁或者引用超出作用于或者被重新赋值时,该对象的引用计数就会减少。
3.可以使用sys.getrefcount()函数来获取对象的当前引用计数。多数情况下,引用计数要比我们猜测的大的多。对于不可变数据(数字和字符串),解释器会在程序的不同部分共享内存,以便节约内存。
垃圾回收机制
特性
1.当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。它会去检查那些引用计数为0的对象,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了。
2.垃圾回收机制还有一个循环垃圾回收器, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。
内存池机制
简介
在Python中,许多时候申请的内存都是小块的内存,这些小块内存在申请后,很快又会被释放,由于这些内存的申请并不是为了创建对象,所以并没有对象一级的内存池机制。这就意味着Python在运行期间会大量地执行malloc和free的操作,频繁地在用户态和核心态之间进行切换,这将严重影响Python的执行效率。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
内存池概念
内存池的概念就是预先在内存中申请一定数量的,大小相等的内存块留作备用,当有新的内存需求时,就先从内存池中分配内存给这个需求,不够了之后再申请新的内存。这样做最显着的优势就是能够减少内存碎片,提升效率。内存池的实现方式有很多,性能和适用范围也不一样。
特性
1.Python提供了对内存的垃圾收集机制,但是它将不用的内存放到内存池而不是返回给操作系统。
2.Pymalloc机制。为了加速Python的执行效率,Python引入了一个内存池机制,用于管理对小块内存的申请和释放。
3.Python中所有小于256个字节的对象都使用pymalloc实现的分配器,而大的对象则使用系统的 malloc。
4.对于Python对象,如整数,浮点数和List,都有其独立的私有内存池,对象间不共享他们的内存池。也就是说如果你分配又释放了大量的整数,用于缓存这些整数的内存就不能再分配给浮点数。

㈧ python 如何释放缓存

我觉得可能是因为你的py文件在第一次启动后,已经编译成pyc文件了,再次启动的时候都是加载pyc,省去了编译的阶段,所以速度很快。
你可以试着把程序目录下的所有pyc或者你的代码文件对应的pyc文件删除,看看是不是可以和第一次加载速度相同

㈨ Python性能提升神器!lru_cache的介绍和讲解

我们经常谈论的缓存一词,更多的类似于将硬盘中的数据存放到内存中以至于提高读取速度,比如常说的redis,就经常用来做数据的缓存。 Python的缓存(lru_cache)是一种装饰在被执行的函数上,将其执行的结果缓存起来,当下次请求的时候,如果请求该函数的传参未变则直接返回缓存起来的结果而不再执行函数的一种缓存装饰器。

那它和redis的区别在哪?有什么优势?怎么使用? 下面为你讲解

1.现在我们先不使用缓存来写一个求两数之和的函数,并调用执行它两次:

执行结果

可以看到 test 被执行了两次,现在我们加上缓存再进行执行:

执行结果

可以看到 test 函数只被执行了一次,第二次的调用直接输出了结果,使用了缓存起来的值。

2.当我们使用递归求斐波拉契数列 (斐波那契数列指的是这样一个数列:0,1,1,2,3,5,8,它从第3项开始,每一项都等于前两项之和) 的时候,缓存对性能的提升就尤其明显了:

不使用缓存求第40项的斐波拉契数列

执行时间

使用缓存求第40项的斐波拉契数列:

执行时间

两个差距是非常明显的,因为不使用缓存时,相当于要重复执行了很多的函数,而使用了 lru_cache 则把之前执行的函数结果已经缓存了起来,就不需要再次执行了。

查看lru_cache源码会发现它可以传递两个参数: maxsize 、 typed :

代表被lru_cache装饰的方法最大可缓存的结果数量 (被装饰方法传参不同一样,则结果不一样;如果传参一样则为同一个结果) , 如果不指定传参则默认值为128,表示最多缓存128个返回结果,当达到了128个时,有新的结果要保存时,则会删除最旧的那个结果。如果maxsize传入为None则表示可以缓存无限个结果;

默认为false,代表不区分数据类型,如果设置为True,则会区分传参类型进行缓存,官方是这样描述的:

但在python3.9.8版本下进行测试,typed为false时,按照官方的测试方法测试得到的还是会被当成不同的结果处理,这个时候typed为false还是为true都会区别缓存,这与官方文档的描述存在差异:

执行结果

但如果是多参数的情况下,则会被当成一个结果:

执行结果

这个时候设置typed为true时,则会区别缓存:

执行结果

当传参个数大于1时,才符合官方的说法,不清楚是不是官方举例有误

当传递的参数是dict、list等的可变参数时,lru_cache是不支持的,会报错:

报错结果

缓存 缓存位置 是否支持可变参数 是否支持分布式 是否支持过期时间设置 支持的数据结构 需单独安装 redis 缓存在redis管理的内存中 是 是 是 支持5种数据结构 是 lru_cache 缓存在应用进程的内存中,应用被关闭则被清空 否 否 否 字典(参数为:key,结果为:value) 否

经过上面的分析,lru_cache 功能相对于redis来说要简单许多,但使用起来更加方便,适用于小型的单体应用。如果涉及的缓存的数据种类比较多并且想更好的管理缓存、或者需要缓存数据有过期时间(类似登录验证的token)等,使用redis是优于lru_cache的。

㈩ Python如何进行内存管理

Python的内存管理,一般从以下三个方面来说:

1)对象的引用计数机制(四增五减)

2)垃圾回收机制(手动自动,分代回收)

3)内存池机制(大m小p)

1)对象的引用计数机制

要保持追踪内存中的对象,Python使用了引用计数这一简单的技术。sys.getrefcount(a)可以查看a对象的引用计数,但是比正常计数大1,因为调用函数的时候传入a,这会让a的引用计数+1

2)垃圾回收机制

吃太多,总会变胖,Python也是这样。当Python中的对象越来越多,它们将占据越来越大的内存。不过你不用太担心Python的体形,它会在适当的时候“减肥”,启动垃圾回收(garbage
collection),将没用的对象清除

从基本原理上,当Python的某个对象的引用计数降为0时,说明没有任何引用指向该对象,该对象就成为要被回收的垃圾了

比如某个新建对象,它被分配给某个引用,对象的引用计数变为1。如果引用被删除,对象的引用计数为0,那么该对象就可以被垃圾回收。

然而,减肥是个昂贵而费力的事情。垃圾回收时,Python不能进行其它的任务。频繁的垃圾回收将大大降低Python的工作效率。如果内存中的对象不多,就没有必要总启动垃圾回收。

所以,Python只会在特定条件下,自动启动垃圾回收。当Python运行时,会记录其中分配对象(object
allocation)和取消分配对象(object deallocation)的次数。当两者的差值高于某个阈值时,垃圾回收才会启动。

我们可以通过gc模块的get_threshold()方法,查看该阈值。

3)内存池机制

Python中有分为大内存和小内存:(256K为界限分大小内存)

1、大内存使用malloc进行分配

2、小内存使用内存池进行分配

python中的内存管理机制都有两套实现,一套是针对小对象,就是大小小于256K时,pymalloc会在内存池中申请内存空间;当大于256K时,则会直接执行系统的malloc的行为来申请内存空间。