缓存的重要性缓存是每个Python程序员都需要理解的一个重要概念。简而言之,缓存的概念主要是使用编程技术将数据存储在临时位置,而不是每次都从源中检索。随后,缓存可以提高应用程序的性能,因为从临时位置访问数据比每次从源(例如数据库、Web服务等)获取数据更快。本文旨在解释缓存在Python中的工作原理。为什么我们需要实现缓存?要了解缓存是什么以及为什么需要缓存,请考虑以下场景。我们正在用Python构建一个应用程序,它将向最终用户显示产品列表。每天有100多个用户多次访问此应用程序。该应用程序将托管在应用程序服务器上,并且可以在Internet上访问。产品将存储在数据库中,该数据库将安装在数据库服务器上。因此,应用服务器会向数据库查询相关记录。下图演示了我们的目标应用程序是如何设置的:问题从数据库中获取数据是一个IO绑定操作。因此,它本质上是缓慢的。如果频繁发送请求而很少更新响应,那么我们可以将响应缓存在应用程序的内存中。我们可以缓存结果,而不是每次都查询数据库:获取数据的请求必须通过网络传输,而响应必须通过网络返回。这本质上是缓慢的。因此,引入了缓存。我们可以缓存结果以减少计算时间并节省计算机资源。缓存是临时存储位置。它适用于延迟加载。最初,缓存是空的。当应用程序服务器从数据库服务器获取数据时,它会用所需的数据集填充缓存。从此之后,后续请求将从缓存中取数据,而不是一路到应用服务器。我们还需要及时使缓存失效,以确保向最终用户显示最新的信息。这就引出了本文的下一部分:缓存规则。缓存规则在我看来,缓存有3条规则。在启用缓存之前,我们需要执行分析应用程序的关键步骤。因此,在应用程序中引入缓存之前的第一步是分析应用程序。只有这样,我们才能了解每个函数需要多长时间以及调用了多少次。分析过程完成后,我们需要确定需要缓存的内容。我们需要一种机制来连接函数的输入和输出并将它们存储在内存中。这就引出了缓存的第一条规则。(1)缓存的第一条规则第一条规则是保证目标函数返回输出的时间长,被频繁执行,函数的输出不经常变化。我们不想为不需要很长时间完成、很少在应用程序中调用或返回源代码中频繁更改的结果的函数引入缓存。这是要记住的重要规则。适合缓存的对象:被频繁调用、输出不经常变化、执行时间长的函数举个例子,如果一个函数执行了100次,并且该函数需要很长时间才能返回结果,并且对于给定的输入它返回相同的结果,那么我们可以缓存结果。但是,如果函数返回的值在源每分钟收到执行该函数的请求之前每秒更新一次,那么了解我们是否需要缓存结果非常重要,因为它最终会向用户发送陈旧数据。这可以帮助我们了解我们是否需要缓存,或者我们是否需要不同的通信通道、数据结构或序列化机制来更快地检索数据,例如通过在套接字上使用二进制序列化程序而不是通过http使用XML序列化来发送数据。此外,了解何时使缓存无效以及何时使用新数据重新加载它也很重要。(2)第二条规则第二条规则是确保从引入的缓存机制中获取数据比执行目标函数更快。只有当从缓存中检索结果比从数据源中检索数据更快时,我们才应该引入缓存。缓存应该比从当前数据源获取数据更快。因此,选择合适的数据结构(如字典或LRU缓存)作为实例至关重要。(3)第三条规则第三条重要规则是关于内存使用的,这一点经常被忽视。您是在执行IO操作,如查询数据库、Web服务,还是在执行CPU密集型操作,如处理数字和执行内存计算?随着我们缓存结果,应用程序的内存占用会增加,所以选择合适的数据结构很关键,只缓存需要缓存的数据属性。有时我们查询多个表来创建一个类的对象。然而,我们只需要在应用程序中缓存基本属性。缓存影响内存占用例如,假设我们构建了一个查询数据库并检索订单列表的报告仪表板。为了便于说明,我们假设仪表板上仅显示订单名称。因此,我们可以只缓存每个订单的名称,而不是缓存整个订单对象。通常,架构师建议创建具有__slots__属性的精简数据传输对象(DTO)以减少内存占用。命名元组或Python数据类也被使用。这导致本文的最后一部分概述了如何实现缓存的细节。缓存是如何实现的?有多种实现缓存的方法。我们可以在Python进程中创建本地数据结构来构建缓存,或者将缓存用作服务器,充当代理并为请求提供服务。有一些内置的Python工具,例如使用functools库中的cached_property装饰器。我想通过提供缓存装饰器属性的概述来介绍缓存的实现。下面的代码片段说明了缓存属性的工作原理。fromfunctoolsimportcached_propertyclassFinTech:@cached_propertydefrun(self):returnlist(range(1,100))结果,FinTech().run现在被缓存并且range(1100)的输出将只生成一次。但是在实际场景中,我们很少需要缓存属性。让我们回顾一下其他方法。1.字典方法对于简单的用例,我们可以创建/使用映射数据结构,如字典,我们可以将其保存在内存中,并使它们在全局框架上可访问。有多种方法可以实现它。最简单的方法是创建一个单例风格的模块,比如config.py中的config.py。我们可以创建一个在开始时填充一次的字典类型字段。从此以后,可以使用字典字段来获取结果。2、最近使用的算法我们可以使用Python自带的特性LRU。LRU代表最近最少使用算法。LRU可以缓存函数的返回值,这取决于传递给函数的参数。LRU在递归CPU绑定操作中特别有用。它本质上是一个装饰器:@lru_cache(maxsize,typed),我们可以用它来装饰函数。maxsize告诉装饰器缓存的最大大小。如果我们不想设置大小,则只需将其设置为None。typed用于指示输出是否要缓存为相同的值,其中可以比较不同类型的值。当我们期望相同的输入产生相同的输出时,这会起作用。将所有数据保存在应用程序的内存中可能会很麻烦。在具有许多进程的分布式应用程序中,这可能会成为一个问题,因为将所有结果缓存在所有进程的内存中是不合适的。一个很好的用例是当应用程序在机器集群上运行时。我们可以将缓存托管为服务。3.缓存即服务第三??种选择是将缓存数据托管为外部服务。该服务可以负责存储所有请求和响应。所有应用程序都可以通过缓存服务检索数据。这就像一个代理。假设我们正在构建一个维基百科大小的应用程序,它将同时或并行地处理1000个请求。我们需要一种缓存机制,并希望在服务器之间分发缓存。我们可以使用内存缓存和缓存数据。Memcached在Linux和Windows中非常流行,因为:它可以用来实现有状态的内存缓存。它甚至可以跨服务器分布。它非常易于使用、快速,并在几个大型组织中得到广泛使用。它支持缓存数据自动过期。我们需要安装一个名为pymemcache的python库。Memcache要求数据以字符串或二进制形式存储。因此,我们必须序列化缓存的对象,并在需要检索它们时反序列化它们。显示如何启动和使用内存缓存的代码片段:client=Client(host,serialiser,deserialiser)client.set('blog':{'name':'caching','publication':'fintechexplained'}}blog=client.get('blog')原始链接:https://medium.com/fintechexplained/advanced-python-how-to-implement-caching-in-python-application-9d0a4136b845
