Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/google-app-engine/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Python类中缓存数据(以避免在App Engine上进行昂贵的文件系统读取)_Python_Google App Engine - Fatal编程技术网

在Python类中缓存数据(以避免在App Engine上进行昂贵的文件系统读取)

在Python类中缓存数据(以避免在App Engine上进行昂贵的文件系统读取),python,google-app-engine,Python,Google App Engine,这个问题并不完全针对应用程序引擎,但它可能有助于了解上下文:我在应用程序引擎上有一种“静态站点生成器”,用于呈现页面,并允许通过各种主题和主题设置对页面进行样式设置。主题当前直接存储在appengine文件系统中,并随应用程序一起上载。主题由一些模板和yaml配置数据组成 为了封装使用主题的工作,我有一个Theme类theme=theme('sunshine')构造了一个主题实例,用于加载和解析名为'sunshine'的主题的配置数据,并允许调用theme.render\u template('

这个问题并不完全针对应用程序引擎,但它可能有助于了解上下文:我在应用程序引擎上有一种“静态站点生成器”,用于呈现页面,并允许通过各种主题和主题设置对页面进行样式设置。主题当前直接存储在appengine文件系统中,并随应用程序一起上载。主题由一些模板和yaml配置数据组成

为了封装使用主题的工作,我有一个
Theme
类<例如,code>theme=theme('sunshine')构造了一个主题实例,用于加载和解析名为'sunshine'的主题的配置数据,并允许调用
theme.render\u template('index.html')
,自动加载和呈现文件系统上的正确文件

问题是,每次有新请求进入并实例化
主题时,加载(尤其是解析主题的(yaml)配置数据)是非常昂贵的。因此,我希望将数据缓存在进程/应用程序引擎实例中,稍后可能会缓存在memcached中

到目前为止,我一直使用非常简单的缓存,如:

class Theme(object):
     _theme_variables_cache = {}

     def __init__(self, name):
         self.name = name

         if name not in Theme._theme_variables_cache:
             Theme._theme_variables[name] = self.load_theme_variables()

...
(我知道,当多个请求同时命中构造函数时,配置可能会被多次读取。但我不认为这会导致问题。)

但这种缓存很快就会变得丑陋。我想从配置文件中读取几个不同的内容,所有缓存都是字典,因为每个不同的主题“name”也指向不同的底层配置

我的最后一个想法是创建一个类似于
主题的函数。_cached_func(func)
,该函数仅在函数结果尚未缓存到特定模板时执行func(请记住,当对象表示不同的模板时,缓存的值也可能不同)。所以我可以像这样使用它:
self.theme\u variables=theme.\u cached\u func(self.load\u theme\u variables())
,但是,我觉得我在这里遗漏了一些明显的东西,因为我对Python还是相当陌生的

是否有一种明显且干净的Python缓存模式可以在这种情况下工作,而不会使整个类的缓存逻辑混乱?我想我不能仅仅通过装饰器或其他东西来记忆函数结果,因为不同的模板必须有不同的缓存。我甚至不需要任何“过时”的缓存处理,因为进程运行时底层配置数据不会更改

更新

最后我就这样做了:

class ThemeConfig(object):
    __instances_cache = {}

    @classmethod
    def get_for(cls, theme_name):
        return cls.__instances_cache.setdefault(
            theme_name, ThemeConfig(theme_name))

    def __init__(self, theme_name):
        self.theme_name = theme_name
        self._load_assets_urls()  # those calls load yaml files
        self._load_variables()
...


class Theme(object):
    def __init__(self, theme_name):
        self.theme_name = theme_name
        self.config = ThemeConfig.get_for(theme_name)
...

因此
ThemeSeconfig
存储从文件系统中读取的主题的所有配置内容,工厂方法
ThemeSeconfig.get\u for
将始终为相同的主题名称分发相同的ThemeSeconfig实例。我仅有的缓存逻辑是工厂方法中的一行,而
主题
对象仍然像往常一样是临时的和非共享的,因此我可以随意使用和滥用它们。

我将尝试一下这一点。基本上,这里可以使用工厂模式来保持主题对象和主题实例的创建之间的清晰边界

工厂本身还可以通过存储主题名称和相应的主题对象之间的映射来维护简单的缓存策略。我将采用以下实施方式:

#the ThemeFactory class instantiates a Theme with a particular name if not present within it's cache
class ThemeFactory(object) :

     def __init__(self):
         self.__theme_variables_cache = {}

     def createTheme(self, theme_name):
         if not self.__theme_variables_cache.contains(name):
              theme = Theme(theme_name)
              self.__theme_variables_cache[name] = theme.load_theme_variables()
          return self.__theme_variables_cache[name]
主题类的定义现在非常清晰和简单,不会包含任何缓存复杂性

class Theme(object):

    def __init__(self, name):
        self.__theme_name = name

    def load_theme_variables(self):
        #contain the logic for loading theme variables from theme files
这种方法具有代码可维护性和责任明确分离的优点(虽然不是完全如此,但factory类仍然维护简单缓存。理想情况下,它应该只引用一个缓存服务或另一个处理缓存的类..但你明白了这一点)

您的主题类做了它最擅长的事情-加载主题变量。因为您有一个工厂模式,所以您将保持客户机代码(使用主题类实例的代码)从创建主题实例的逻辑中封装。随着应用程序的增长,您可以扩展此工厂来控制各种主题对象(包括从主题派生的类)的创建

注意,这只是实现简单缓存行为和实例创建封装的一种方法

还有一点-您可以在缓存中存储主题对象,而不是主题变量。通过这种方式,您可以仅在第一次使用时从模板读取主题变量(延迟加载)。但是,在这种情况下,您需要确保将主题变量存储为主题类的实例变量。方法
load\u theme\u variables(self)
现在需要这样编写:

def load_theme_variables(self):
   #let the theme variables be stored in an instance variable __theme_variable
   if not self.__theme_variables is None:
       return self.__theme_variables
    #__read_theme_file is a private function that reads the theme files
   self__theme_variables = self.__read_theme_file(self.__theme_name)

希望这能让您了解如何实现您的用例。

看看webapp2.cached_属性中的缓存机制。您可以使用类似的设计实现dict。@据我所知,webapp2.cached_属性修改属性,使其计算结果替换为其结果,以便下一次查找只获得结果,而不调用该方法,对吗?我想我可以通过某种方式对它进行修补,以便它检查是否已经对引用相同主题名称的主题对象调用了相同的方法,然后只返回缓存结果。但我觉得这有点太神奇了。不知道我是否还记得两周后我做了什么。或者您还有其他想法吗?cached_属性只在单个请求中缓存,因此在这种情况下可能没有用处。请注意,这是缓存到ThemeFactory实例,而不是类。这意味着您必须保留一个ThemeFactory实例