Python开发:缓存机制介绍
创始人
2025-01-27 19:10:35
0次

【51CTO快译】在今天的文章中,我们将一同从简单示例出发,了解如何使用缓存机制。在此之后,我们将进一步利用Python标准库的functools模块创建适合自己需要的缓存。闲言少叙,马上开始。

缓存是一种将定量数据加以保存以备迎合后续请求的处理方式,旨在加快数据的检索速度。在今天的文章中,我们将一同从简单示例出发,了解如何使用缓存机制。在此之后,我们将进一步利用Python标准库的functools模块创建适合自己需要的缓存。作为起步工作,我们首先创建一个类,用于构建我们的缓存字典,而后根据需要进行扩展。以下为具体代码:

  1. ######################################################################## 
  2.  
  3. class MyCache: 
  4.  
  5.     """""" 
  6.  
  7.     #---------------------------------------------------------------------- 
  8.  
  9.     def __init__(self): 
  10.  
  11.         """Constructor""" 
  12.  
  13.         self.cache = {} 
  14.  
  15.         self.max_cache_size = 10 

在以上类示例中没有包含什么特别之处。我们只是创建一个简单类,同时设置两个类变量或者说属性,即cahce与max_cache_size。其中cache属于一套空字典,而max_cache_size显然代表着***缓存容量。下面让我们进一步充实该代码,使其具备一定功能:

  1. import datetime 
  2.  
  3. import random 
  4.  
  5. ######################################################################## 
  6.  
  7. class MyCache: 
  8.  
  9.     """""" 
  10.  
  11.     #---------------------------------------------------------------------- 
  12.  
  13.     def __init__(self): 
  14.  
  15.         """Constructor""" 
  16.  
  17.         self.cache = {} 
  18.  
  19.         self.max_cache_size = 10 
  20.  
  21.     #---------------------------------------------------------------------- 
  22.  
  23.     def __contains__(self, key): 
  24.  
  25.         """ 
  26.  
  27.         根据该键是否存在于缓存当中返回True或者False 
  28.  
  29.         """ 
  30.  
  31.         return key in self.cache 
  32.  
  33.     #---------------------------------------------------------------------- 
  34.  
  35.     def update(self, key, value): 
  36.  
  37.         """ 
  38.  
  39.         更新该缓存字典,您可选择性删除最早条目 
  40.  
  41.         """ 
  42.  
  43.         if key not in self.cache and len(self.cache) >= self.max_cache_size: 
  44.  
  45.             self.remove_oldest() 
  46.  
  47.         self.cache[key] = {'date_accessed': datetime.datetime.now(), 
  48.  
  49.                            'value': value} 
  50.  
  51.     #---------------------------------------------------------------------- 
  52.  
  53.     def remove_oldest(self): 
  54.  
  55.         """ 
  56.  
  57.         删除具备最早访问日期的输入数据 
  58.  
  59.         """ 
  60.  
  61.         oldest_entry = None 
  62.  
  63.         for key in self.cache: 
  64.  
  65.             if oldest_entry == None: 
  66.  
  67.                 oldest_entry = key 
  68.  
  69.             elif self.cache[key]['date_accessed'] < self.cache[oldest_entry][ 
  70.  
  71.                 'date_accessed']: 
  72.  
  73.                 oldest_entry = key 
  74.  
  75.         self.cache.pop(oldest_entry) 
  76.  
  77.     #---------------------------------------------------------------------- 
  78.  
  79.     @property 
  80.  
  81.     def size(self): 
  82.  
  83.         """ 
  84.  
  85.         返回缓存容量大小 
  86.  
  87.         """ 
  88.  
  89.         return len(self.cache) 

在这里,我们导入了datetime与random模块,而后我们即可看到之前创建完成的类。这一次,我们向其中添加几种方法。其中一种方法具备神奇的效果,名为_contains_。虽然在这里并不一定要使用该方法,但其基本思路在于允许我们检查该类实例,从而了解其中是否包含有我们正在寻找的键。另外,update方法负责利用新的键/值对进行缓存字典更新。一旦达到或者超出缓存***容量,其还会删除日期最早的输入数据。另外,remove_oldest方法负责具体的字典内早期数据删除工作。***,我们还引入了名为size的属性,其能够返回缓存的具体容量。

在添加了以下代码之后,我们就能够测试该缓存是否按预期起效:

  1. if __name__ == '__main__': 
  2.  
  3.     #测试缓存 
  4.  
  5.     keys = ['test', 'red', 'fox', 'fence', 'junk', 
  6.  
  7.             'other', 'alpha', 'bravo', 'cal', 'devo', 
  8.  
  9.             'ele'] 
  10.  
  11.     s = 'abcdefghijklmnop' 
  12.  
  13.     cache = MyCache() 
  14.  
  15.     for i, key in enumerate(keys): 
  16.  
  17.         if key in cache: 
  18.  
  19.             continue 
  20.  
  21.         else: 
  22.  
  23.             value = ''.join([random.choice(s) for i in range(20)]) 
  24.  
  25.             cache.update(key, value) 
  26.  
  27.         print("#%s iterations, #%s cached entries" % (i+1, cache.size)) 
  28.  
  29.     print 

在本示例当中,我们设置了大量预定义键与循环。如果键尚不存在,我们会将其添加到缓存当中。不过以上示例代码并没有提到如何更新访问日期,感兴趣的朋友们可以将其作为练习自行探索。在运行这段代码之后,大家会注意到当缓存被占满时,其会正确删除时间更早的条目。

现在,我们继续前进,看看如何利用另一种方式使用Python的内置functools模块创建缓存。

使用functools.lru_cache

Python的functools模块提供一种非常实用的装饰器,即lru_cache。需要注意的是,其在3.2版本当中才被添加进来。根据说明文档所言,该装饰器能够“利用可调用内存对函数进行打包,从而削减最近调用的***尺寸。”接下来,我们将根据说明文档中提到的示例编写一项基本功能,其中包含多个网络页面。在这种情况下,我们可以直接从Python说明文档站点处获取页面。

  1. import urllib.error 
  2.  
  3. import urllib.request 
  4.  
  5. from functools import lru_cache 
  6.  
  7. @lru_cache(maxsize=24) 
  8.  
  9. def get_webpage(module): 
  10.  
  11.     """ 
  12.  
  13.     获取特定Python模块网络页面 
  14.  
  15.     """     
  16.  
  17.     webpage = "https://docs.python.org/3/library/{}.html".format(module) 
  18.  
  19.     try: 
  20.  
  21.         with urllib.request.urlopen(webpage) as request: 
  22.  
  23.             return request.read() 
  24.  
  25.     except urllib.error.HTTPError: 
  26.  
  27.         return None 
  28.  
  29. if __name__ == '__main__': 
  30.  
  31.     modules = ['functools', 'collections', 'os', 'sys'] 
  32.  
  33.     for module in modules: 
  34.  
  35.         page = get_webpage(module) 
  36.  
  37.         if page: 
  38.  
  39.             print("{} module page found".format(module)) 

在以上代码当中,我们利用lru_cache对get_webpage函数进行了装饰,并将其***尺寸设置为24条调用。在此之后,我们设置了一条网页字符串变量,并将其传递至我们希望函数获取的模块当中。根据我的个人经验,如果大家将其运行在某种Python解释器当中——例如IDLE——那么效果会更好。如此一来,我们就能够针对该函数运行多次循环。可以看到在***运行上述代码时,输出结果的显示速度相对比较慢。但如果大家在同一会话中再次加以运行,那么其显示速度将极大加快——这意味着lru_cache已经正确对该调用进行了缓存处理。大家可以在自己的解释器实例当中进行试验并亲自查看结果。

另外,我们还可以将一条typed参数传递至该装饰器。其属于一条Boolean,旨在通知该装饰器在typed为设定为True时对不同类型参数进行分别缓存。

总结

现在大家已经初步了解了如何利用Python编写自己的缓存机制。这是一款有趣的工具,而且能够在各位面对大量高强度I/O调用或者希望对登录凭证等常用信息进行缓存时发挥重要作用。

原文标题:Python开发:缓存机制介绍

【51CTO译稿,合作站点转载请注明原文译者和出处为51CTO.com】

相关内容

热门资讯

PHP新手之PHP入门 PHP是一种易于学习和使用的服务器端脚本语言。只需要很少的编程知识你就能使用PHP建立一个真正交互的...
网络中立的未来 网络中立性是什... 《牛津词典》中对“网络中立”的解释是“电信运营商应秉持的一种原则,即不考虑来源地提供所有内容和应用的...
各种千兆交换机的数据接口类型详... 千兆交换机有很多值得学习的地方,这里我们主要介绍各种千兆交换机的数据接口类型,作为局域网的主要连接设...
粉嫩如何诠释霸道 东芝M805... “霸道粉”是个什么玩意东芝M805拿过来的时候,笔者扑哧笑了,不是笑这款笔记本,而是笑这款产品的颜色...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
什么是大数据安全 什么是大数据... 在《为什么需要大数据安全分析》一文中,我们已经阐述了一个重要观点,即:安全要素信息呈现出大数据的特征...
只需三步,让你掌握阿尔法路由器... 请参照以下阿尔法路由器设置方法,通过浏览器进入及设置宽带路由器。经过这三个步骤的设置,基本上能够熟悉...
全面诠释网络负载均衡 负载均衡的出现大大缓解了服务器的压力,更是有效的利用了资源,提高了效率。那么我们现在来说一下网络负载...
如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何更省钱? 近期特价热门硒鼓... 如今激光打印设备已经成为商务或企业的绝对主力办公设备,但采购者往往忽视了激光打印设备所用的耗材,相对...