2

我第一次尝试在 App Engine 上使用 memcache 并遇到“PicklingError”。

我尝试使用 memcache 的第一个地方是在网站的主页上,我从数据存储中获取内容:

def get(self):
    content = memcache.get('home:content')
    if content is None:
        all_content = Content.all()
        all_content.order("-views")
        all_content.filter('published =', True)
        content = all_content.run(batch_size=5, limit=5)
        memcache.add(key='home:content', value=content, time=120)

(请注意,无需我尝试将内容 Query 对象放入 memcache 即可正常工作。这是它在最后一行遇到的错误(memcache.add ...):

PicklingError: Pickling of datastore_query.Batcher is unsupported.

这是内容的模型:

class Content(db.Model):
    category = db.StringProperty(required = True)
    content_type = db.StringProperty(required = True)
    published = db.BooleanProperty(default = False)
    title = db.StringProperty(required = True)
    abstract = db.TextProperty(required = True)
    summary = db.TextProperty(required = True)
    URL = db.LinkProperty(required = True)
    youtube_id = db.StringProperty(required = False)
    thumbnail = db.LinkProperty(required = True)
    post_author = db.StringProperty(required = True)
    author_url = db.LinkProperty(required = False)
    date_post = db.DateTimeProperty(required = True, auto_now_add = True)
    date_source = db.DateTimeProperty(required = False)    
    # todo: split out to use decent shardedcounter approach
    views = db.IntegerProperty(default = 0)
    up_votes = db.IntegerProperty(default = 0)
    down_votes = db.IntegerProperty(default = 0)    
    def votes(self):
        return self.up_votes - self.down_votes

我正在努力弄清楚 PicklingError 是什么以及它与尝试将 Query 对象存储到内存缓存中的关系。我的问题:我做错了什么?这是因为我试图缓存迭代器吗?缓存 Query 对象并需要在每次页面加载时对其调用 .run() 是否有任何价值?

4

1 回答 1

2

看看代码memcache

简而言之,这是因为您的值必须以简单的方式序列化,因此默认情况下pickle(实际上cPickle)用于序列化您传入的对象。

add被调用时,_set_with_policy被调用,随后调用_set_multi_async_with_policy。在_set_multi_async_with_policy中,键值对作为传入mapping在循环中序列化

for key, value in mapping.iteritems():
  server_key = _key_string(key, key_prefix, user_key)
  stored_value, flags = _validate_encode_value(value, self._do_pickle)

在辅助方法_validate_encode_value中,如果传入的对象不是可识别的对象,例如int, bool, str,则该方法会尝试腌制该对象:

else:
  stored_value = do_pickle(value)
  flags |= TYPE_PICKLED

更新:当您调用 run 时,您会得到一个迭代器对象,其中包含查询中包含的某些对象。如果您只想腌制结果,则可以将此迭代器通过以下方式转换为列表

content = list(all_content.run(batch_size=5, limit=5))

如果您想保留其他部分,则需要某种自定义pickler。如您所见Batcher

  def __getstate__(self):
    raise pickle.PicklingError(
        'Pickling of datastore_query.Batch is unsupported.')

中定义的大多数类——与定义大多数查询行为的类完全相同——强烈反对通过调用when来datastore_query进行酸洗。如果您从未使用过它,并且是有助于腌制和解封对象的自定义方法。PicklingError__getstate____getstate____setstate__

于 2012-11-23T18:50:08.350 回答