无法使Beaker缓存正常工作

1 投票
3 回答
1316 浏览
提问于 2025-04-16 00:46

我正在尝试使用Beaker的缓存库,但我就是搞不定它。

这是我的测试代码。

class IndexHandler():
    @cache.cache('search_func', expire=300)
    def get_results(self, query):
        results = get_results(query)
        return results

    def get(self, query):
        results = self.get_results(query)
        return render_index(results=results)

我试过Beaker文档里的例子,但我看到的都是

<type 'exceptions.TypeError'> at /
can't pickle generator objects

显然我漏掉了什么,但我找不到解决办法。

顺便说一下,这个问题发生在缓存类型设置为“文件”的时候。

3 个回答

1

试试用 return list(results) 代替 return results,看看这样是否有效。

这个 beaker 文件缓存需要能够把缓存的键和值都保存下来;但是大多数的迭代器和生成器是不能被保存的。

1

我注意到beaker的文档没有明确提到这一点,但很明显,decorate函数必须把它调用时的参数进行序列化(也就是“打包”),这样才能用这些参数作为缓存的关键字,检查缓存中是否有这个条目,如果没有的话再添加进去。而生成器对象是不能被序列化的,这就是你看到的错误信息所说的。所以,这意味着query很可能是一个生成器对象。

为了使用beaker或者其他类型的缓存,你应该传递的是可以被序列化的parameters,而不是query生成器对象。也就是说,你可以传递字符串、数字、字典、列表、元组等等,任何你觉得方便的组合方式,这样就能在get_results函数内部“及时”构建出查询。这种方式下,参数是可以被序列化的,缓存也能正常工作。

如果方便的话,你可以创建一个简单的可序列化类,这个类的实例可以“代表”查询,模拟你需要的初始化和参数设置,并且只有在调用某个需要实际查询对象的方法时才进行即时创建。但这只是一个“方便”的想法,并不会改变前面提到的基本概念。

3

如果你把beaker配置成保存到文件系统,你会发现每个参数也会被序列化(也就是变成一种可以存储的格式)。举个例子:

tp3
sS'tags <myapp.controllers.tags.TagsController object at 0x103363c10> <MySQLdb.cursors.Cursor object at 0x103363dd0> apple'
p4

注意缓存的“键”不仅仅包含我的关键词“apple”,还包含了一些特定于实例的信息。这其实很糟糕,因为特别是‘self’在每次调用时都不会相同。这样缓存每次都会失效(而且会被一些没用的键填满)。

带有缓存注解的方法应该包含与你想要的“键”相对应的参数。换句话说,假设你想存储“John”对应的值555-1212,并且想要缓存这个信息。你的函数只应该接受一个字符串作为参数。你传入的任何参数在每次调用时都应该保持不变,所以像“self”这样的参数就不合适。

让这个工作变得简单的一种方法是把函数内联,这样你就不需要传递除了键以外的其他东西。例如:

def index(self):

    # some code here

    # suppose 'place' is a string that you're using as a key. maybe
    # you're caching a description for cities and 'place' would be "New York"
    # in one instance

    @cache_region('long_term', 'place_desc')
    def getDescriptionForPlace(place):
      # perform expensive operation here
      description = ...
      return description

    # this will either fetch the data or just load it from the cache
    description = getDescriptionForPlace(place)

你的缓存文件应该看起来像下面这样。注意只有'place_desc'和'John'被保存为键。

tp3 
sS'place_desc John' 
p4

撰写回答