Один из способов сделать это быстрее - превратить вашу модель в словарь и использовать собственную функцию eval/repr в качестве сериализаторов (de) с осторожностью, как всегда со злым eval, но это должно быть здесь безопасным, поскольку нет внешнего шага.
Ниже приведен пример класса Fake_entity, реализующего именно это. Вы сначала создаете свой словарь через fake = Fake_entity(entity)
, тогда вы можете просто сохранить свои данные через memcache.set(key, fake.serialize())
. Сериализация() является простым вызовом метода родного словаря для публикации, с некоторыми дополнениями, если вам нужно (например, добавить идентификатор в начале строки).
Чтобы получить его обратно, просто используйте 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 (созданного), а также эталонные свойства (поддомена):
### FAKE МОДЕЛЬ СУЩНОСТЬ ###
{ 'статус': u'admin', 'session_expiry': Нет, ' first_name ': u'Louis', 'last_name': u'Le Sieur ',' 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'
[email protected] ',' key ':' agdqZXJlZ2xlcgwLEgVMb2dpbhjmAQw ',' session_ref ': None,' _cls ':' models.Login ',' groups ': [],' email___password_hash ': u'
[email protected]+a9993e364706816aba3e25717000000000000000', 'subdomain': datastore_types.Key.from_path (u'Subdomain ' , 229L, _app = u'jeregle '),' allowed ': [],' permissions ': []}
Лично я также использую статические переменные (быстрее, чем memcache) для кэширования моих объектов в краткосрочной перспективе, и извлекает хранилище данных, когда сервер изменился, или по какой-то причине его память покраснела (что часто случается довольно часто) ,
Я просто попробовал его с действительно большими и сложными моделями, но результат был примерно такой же. –
Возможно, на GAE есть http://docs.python.org/library/timeit.html? Это должно показать более точные результаты, но все же - после прочтения записи в блоге, с которой вы связались, я ожидал бы разницу в величине разницы между производительностью protobuffers и pickle - и это должно быть уловлено time.time() в любом случае .. –
i'm используя java appengine, поэтому я слишком ленив, чтобы проверить эту теорию, - это pickle() кэширование результатов за кулисами где-то, а to_protobuf - нет? Основываясь на этой статье, я не уверен, что ожидаю полного увеличения величины скорости, поскольку рассол все еще называется даже с использованием версии protobuf. однако используемое пространство, безусловно, может быть значительно меньше. –