首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >做AppEngine模型内存缓存的最好方法是什么?

做AppEngine模型内存缓存的最好方法是什么?
EN

Stack Overflow用户
提问于 2010-02-20 05:21:51
回答 3查看 3.4K关注 0票数 16

目前,我的应用程序在memcache中缓存模型,如下所示:

memcache.set("somekey", aModel)

但Nicks在http://blog.notdot.net/2009/9/Efficient-model-memcaching上的帖子表明,首先将其转换为protobuffers要高效得多。但在运行了一些测试后,我发现它确实更小,但实际上更慢(~10%)。

是其他人也有同样的经历,还是我做错了什么?

测试结果:http://1.latest.sofatest.appspot.com/?times=1000

import pickle
import time
import uuid

from google.appengine.ext import webapp
from google.appengine.ext import db
from google.appengine.ext.webapp import util
from google.appengine.datastore import entity_pb
from google.appengine.api import memcache

class Person(db.Model):
 name = db.StringProperty()

times = 10000

class MainHandler(webapp.RequestHandler):

 def get(self):

  self.response.headers['Content-Type'] = 'text/plain'

  m = Person(name='Koen Bok')

  t1 = time.time()

  for i in xrange(int(self.request.get('times', 1))):
   key = uuid.uuid4().hex
   memcache.set(key, m)
   r = memcache.get(key)

  self.response.out.write('Pickle took: %.2f' % (time.time() - t1))


  t1 = time.time()

  for i in xrange(int(self.request.get('times', 1))):
   key = uuid.uuid4().hex
   memcache.set(key, db.model_to_protobuf(m).Encode())
   r = db.model_from_protobuf(entity_pb.EntityProto(memcache.get(key)))


  self.response.out.write('Proto took: %.2f' % (time.time() - t1))


def main():
 application = webapp.WSGIApplication([('/', MainHandler)], debug=True)
 util.run_wsgi_app(application)


if __name__ == '__main__':
 main()
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-03-01 06:00:11

Memcache调用仍然使用或不使用protobuf来pickles对象。Pickle使用protobuf对象更快,因为它有一个非常简单的模型

普通的pickle对象比protobuf+pickle对象大,因此它们节省了Memcache上的时间,但是在进行protobuf转换时有更多的处理器时间

因此,一般而言,这两种方法都适用于same...but

你应该使用protobuf的原因是它可以处理模型版本之间的变化,而Pickle会出错。这个问题总有一天会让你头疼,所以最好早点处理。

票数 4
EN

Stack Overflow用户

发布于 2010-03-15 06:58:44

pickle和protobufs在App Engine中都很慢,因为它们是用纯Python实现的。我发现使用像str.join这样的方法编写我自己的简单序列化代码往往更快,因为大多数工作都是用C完成的,但这只适用于简单的数据类型。

票数 1
EN

Stack Overflow用户

发布于 2010-07-21 02:43:27

一种更快的方法是将模型转换为字典,并使用本机eval / repr函数作为(反)序列化程序--当然要小心,就像使用邪恶的eval一样,但这里应该是安全的,因为没有外部步骤。

下面是一个类Fake_entity的例子,它就是这样实现的。首先,您可以通过fake = Fake_entity(entity)创建字典,然后您可以简单地通过memcache.set(key, fake.serialize())存储数据。serialize()是对repr的本机字典方法的简单调用,如果需要,可以添加一些内容(例如,在字符串的开头添加一个标识符)。

要取回它,只需使用fake = Fake_entity(memcache.get(key))即可。Fake_entity对象是一个简单的字典,它的键也可以作为属性访问。你可以正常地访问你的实体属性,除了referenceProperties给出键而不是获取对象(这实际上非常有用)。您还可以使用fake.get()获取()实际的实体,或者更有趣的是,更改它,然后使用fake.put()保存它。

它不适用于列表(如果您从查询中获取多个实体),但可以使用诸如'### FAKE MODEL ENTITY ###‘这样的标识符作为分隔符,通过连接/拆分函数轻松地进行调整。仅与db.Model一起使用,需要对Expando进行小的调整。

class Fake_entity(dict):
    def __init__(self, record):
        # simple case: a string, we eval it to rebuild our fake entity
        if isinstance(record, basestring):
            import datetime # <----- put all relevant eval imports here
            from google.appengine.api import datastore_types
            self.update( eval(record) ) # careful with external sources, eval is evil
            return None

        # serious case: we build the instance from the actual entity
        for prop_name, prop_ref in record.__class__.properties().items():
            self[prop_name] = prop_ref.get_value_for_datastore(record) # to avoid fetching entities
        self['_cls'] = record.__class__.__module__ + '.' + record.__class__.__name__
        try:
            self['key'] = str(record.key())
        except Exception: # the key may not exist if the entity has not been stored
            pass

    def __getattr__(self, k):
        return self[k]

    def __setattr__(self, k, v):
        self[k] = v

    def key(self):
        from google.appengine.ext import db
        return db.Key(self['key'])

    def get(self):
        from google.appengine.ext import db
        return db.get(self['key'])

    def put(self):
        _cls = self.pop('_cls') # gets and removes the class name form the passed arguments
        # import xxxxxxx ---> put your model imports here if necessary
        Cls = eval(_cls) # make sure that your models declarations are in the scope here
        real_entity = Cls(**self) # creates the entity
        real_entity.put() # self explanatory
        self['_cls'] = _cls # puts back the class name afterwards
        return real_entity

    def serialize(self):
        return '### FAKE MODEL ENTITY ###\n' + repr(self)
        # or simply repr, but I use the initial identifier to test and eval directly when getting from memcache

我欢迎这方面的速度测试,我假设这比其他方法要快得多。此外,如果您的模型在此期间以某种方式进行了更改,则不会有任何风险。

下面是序列化的伪实体的示例。请特别查看datetime (已创建)以及引用属性(子域):

伪模型实体

{'status':U‘’admin‘,'session_expiry':None,'first_name':U’路易斯‘,'last_name':U’‘Le’,'modified_by':None,'password_hash':u'a9993e364706816aba3e25717000000000000000','language':U‘’fr‘,'created':datetime.datetime(2010,7,18,21,50,11,750000),'modified':None,'created_by':None,'email':U’‘chou@glou.bou’,‘'key':'agdqZXJlZ2xlcgwLEgVMb2dpbhjmAQw','session_ref':无,'_cls':'models.Login','groups':[],’email__password_hash‘:u'chou@glou.bou+a9993e364706816aba3e25717000000000000000',’子域‘:datastore_types.Key.from_path(u’子域‘,229L,_app=u’‘jeregle’),‘允许’:[],‘权限’:[]}

就我个人而言,我还使用静态变量(比memcache更快)在短期内缓存我的实体,并在服务器发生更改或其内存由于某种原因被刷新时获取数据存储(事实上,这种情况经常发生)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2299680

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档