Skip to content
This repository has been archived by the owner on May 13, 2020. It is now read-only.

Commit

Permalink
* Overwrite some methods that UserDict just implements inefficiently.
Browse files Browse the repository at this point in the history
  This gave me an 8-10% improvement in my performance tests.

* Added a hook for doing a proper object cache later.
  • Loading branch information
strichter committed Apr 3, 2012
1 parent acebf0b commit 4216519
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 30 deletions.
79 changes: 51 additions & 28 deletions src/mongopersist/performance.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#
##############################################################################
"""Mongo Persistence Performance Test"""
from __future__ import absolute_import
import optparse
import persistent
import pymongo
Expand Down Expand Up @@ -72,24 +73,25 @@ def run_basic_crud(options):
else:
people = dm.root['people']

# Profile slow read
transaction.begin()
t1 = time.time()
[people[name].name for name in people]
#cProfile.runctx(
# '[people[name].name for name in people]', globals(), locals())
t2 = time.time()
transaction.commit()
print 'Slow Read: %.4f secs' % (t2-t1)

# Profile fast read (values)
transaction.begin()
t1 = time.time()
[person.name for person in people.values()]
#cProfile.runctx(
# '[person.name for person in people.find()]', globals(), locals())
t2 = time.time()
print 'Fast Read (values): %.4f secs' % (t2-t1)
# # Profile slow read
# transaction.begin()
# t1 = time.time()
# [people[name].name for name in people]
# #cProfile.runctx(
# # '[people[name].name for name in people]', globals(), locals())
# t2 = time.time()
# transaction.commit()
# print 'Slow Read: %.4f secs' % (t2-t1)
#
# # Profile fast read (values)
# transaction.begin()
# t1 = time.time()
# [person.name for person in people.values()]
# #cProfile.runctx(
# # '[person.name for person in people.find()]', globals(), locals())
# t2 = time.time()
# transaction.commit()
# print 'Fast Read (values): %.4f secs' % (t2-t1)

# Profile fast read
transaction.begin()
Expand All @@ -98,20 +100,41 @@ def run_basic_crud(options):
#cProfile.runctx(
# '[person.name for person in people.find()]', globals(), locals())
t2 = time.time()
cache = [
(person.__class__,
people._p_oid,
people._p_jar._writer.get_full_state(person),
)
for person in people.values()]
transaction.commit()
print 'Fast Read (find): %.4f secs' % (t2-t1)

# Profile modification
# Profile fast read (cache)
transaction.begin()
t1 = time.time()
def modify():
for person in list(people.find()):
person.name += 'X'
person.age += 1
transaction.commit()
modify()
#cProfile.runctx(
# 'modify()', globals(), locals())
def read():
for klass, dbref, doc in cache:
person = people._p_jar._reader.get_ghost(dbref, klass)
people._p_jar._reader.set_ghost_state(person, doc)
person.name
cProfile.runctx('read()', globals(), locals())
#read()
t2 = time.time()
print 'Modification: %.4f secs' % (t2-t1)
transaction.commit()
print 'Fast Read (cache): %.4f secs' % (t2-t1)

# # Profile modification
# t1 = time.time()
# def modify():
# for person in list(people.find()):
# person.name += 'X'
# person.age += 1
# transaction.commit()
# modify()
# #cProfile.runctx(
# # 'modify()', globals(), locals())
# t2 = time.time()
# print 'Modification: %.4f secs' % (t2-t1)

if options.delete:
# Profile deletion
Expand Down
25 changes: 23 additions & 2 deletions src/mongopersist/serialize.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,26 @@ def get_dotted_name(obj):
class PersistentDict(persistent.dict.PersistentDict):
_p_mongo_sub_object = True

def __init__(self, data=None, **kwargs):
# We optimize the case where data is not a dict. The original
# implementation always created an empty dict, which it then
# updated. This turned out to be expensive.
if data is None:
self.data = {}
elif isinstance(data, dict):
self.data = data.copy()
else:
self.data = dict(data)
if len(kwargs):
self.update(kwargs)

def __getitem__(self, key):
# The UserDict supports a __missing__() function, which I have never
# seen or used before, but it makes the method significantly
# slower. So let's not do that.
return self.data[key]


class PersistentList(persistent.list.PersistentList):
_p_mongo_sub_object = True

Expand Down Expand Up @@ -513,13 +533,14 @@ def set_ghost_state(self, obj, doc=None):
# Set the state.
obj.__setstate__(state)

def get_ghost(self, dbref):
def get_ghost(self, dbref, klass=None):
# If we can, we return the object from cache.
try:
return self._jar._object_cache[dbref.id]
except KeyError:
pass
klass = self.resolve(dbref)
if klass is None:
klass = self.resolve(dbref)
obj = klass.__new__(klass)
obj._p_jar = self._jar
obj._p_oid = dbref
Expand Down

0 comments on commit 4216519

Please sign in to comment.