더 빨리 수행하는 한 가지 방법은 모델을 사전으로 변환하고 악의적 인 평가와 마찬가지로주의 깊게 (비) 시리얼 라이저로 원시 eval/repr 함수를 사용하는 것입니다. 외부적인 조치가 없다는 점을 고려할 때 여기에서 안전해야합니다.
다음은 정확히 구현 한 Fake_entity의 예입니다. 먼저 사전을 fake = Fake_entity(entity)
으로 작성한 다음 memcache.set(key, fake.serialize())
을 통해 데이터를 저장할 수 있습니다. serialize()는 repr의 네이티브 사전 메서드에 대한 간단한 호출이며 필요할 경우 추가 할 수 있습니다 (예 : 문자열의 시작 부분에 식별자를 추가).
다시 가져 오려면 fake = Fake_entity(memcache.get(key))
을 사용하면됩니다. Fake_entity 객체는 키가 속성으로 액세스 할 수있는 간단한 사전입니다. referenceProperties가 객체를 가져 오는 대신 키를 제공한다는 점을 제외하면 엔티티 속성에 정상적으로 액세스 할 수 있습니다 (실제로 유용합니다). 또한 실제 엔티티를 fake.get() 또는 더 관심있게 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
속도 테스트를 환영합니다. 다른 접근 방식보다 훨씬 빠르다고 생각합니다. 또한 그동안 모델이 어떻게 든 변경된 경우 위험이 없습니다.
다음은 직렬화 된 위조 된 엔티티의 모습입니다.특정 (생성) 날짜 봐뿐만 아니라 참조 속성 (하위 도메인)을 가지고 :
### 가짜 모델의 ENTITY ###
{ '상태'u'admin ','session_expiry '없음' u'Le Sieur ','modified_by ': 없음,'password_hash ': u'a9993e364706816aba3e25717000000000000000', 'language': u'fr ','created ': datetime.datetime ('이름 ','이름 ' 2010, 7, 18, 21, 50, 11, 750000), 'modified': 없음, 'created_by': 없음, 'email': u'
[email protected] ','key ':'agdqZXJLZ2xlcgwLEgVMb2dpbhjmAQw ','session_ref ':'_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()에 의해 잡혀 있어야합니다 .. –
나는 java appengine을 사용하여이 이론을 테스트하기에는 너무 게으른 편이다. to_protobuf가 아닌 반면에 어딘가에서 결과를 캐싱하는 pickle()인가? 이 기사를 토대로 필자는 protobuf 버전을 사용해도 여전히 피클이 호출됨에 따라 속도가 엄청나게 빨라질 것이라고 기대하지는 않는다. 사용 된 공간은 분명히 훨씬 더 작을 수 있습니다. –