我正在尝试使用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
显然我错过了一些东西,但我找不到解决方案。
顺便提一下,如果缓存类型设置为“file”,则会出现此问题。
答案 0 :(得分:3)
如果将beaker配置为保存到文件系统,则可以很容易地看到每个参数也被腌制。例如:
tp3
sS'tags <myapp.controllers.tags.TagsController object at 0x103363c10> <MySQLdb.cursors.Cursor object at 0x103363dd0> apple'
p4
请注意,缓存“key”不仅包含我的关键字“apple”,还包含特定于实例的信息。这非常糟糕,因为特别是“自我”在调用中不会相同。缓存每次都会导致错过(并且会填满无用的密钥。)
使用缓存注释的方法应该仅具有与您想到的任何“密钥”对应的参数。换句话说,假设您想要存储“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
答案 1 :(得分:1)
我看到beaker
文档没有明确提到这一点,但是,显然,decorate函数必须挑选它所调用的参数(用作密钥的一部分进入缓存,以检查条目存在,并在以后添加它) - 并且,生成器对象不是pickleable,因为错误消息告诉你。这意味着query
当然是一个生成器对象。
为了使用烧杯或任何其他类型的缓存,您应该做的是传递({pickleable)query
而不是parameters
生成器对象,该查询可以是内置 - 字符串,数字,dicts,列表,元组等等,以任何方式组成,易于安排,并且只在{{1}的函数体内“及时”构建查询}}。这样,参数将是可选择的,缓存将起作用。
如果方便,您可以构建一个简单的pickleable类,其实例“代表”查询,模拟您需要的任何初始化和参数设置,并仅在需要实际查询对象的某些方法时执行实时实例化调用。但这只是一个“方便”的想法,并没有像前一段所解释的那样改变基本概念。
答案 2 :(得分:1)
尝试使用return list(results)
代替return results
,看看是否有帮助。
beaker文件缓存需要能够腌制缓存键和值;大多数迭代器和生成器都是不可用的。