[Checkins] SVN: mongopersist/trunk/src/mongopersist/ * Overwrite some methods that UserDict just implements inefficiently.

Stephen Richter cvs-admin at zope.org
Tue Apr 3 18:22:51 UTC 2012


Log message for revision 124923:
  * Overwrite some methods that UserDict just implements inefficiently. 
    This gave me an 8-10% improvement in my performance tests.
  
  * Added a hook for doing a proper object cache later.
  

Changed:
  U   mongopersist/trunk/src/mongopersist/performance.py
  U   mongopersist/trunk/src/mongopersist/serialize.py

-=-
Modified: mongopersist/trunk/src/mongopersist/performance.py
===================================================================
--- mongopersist/trunk/src/mongopersist/performance.py	2012-04-03 18:20:33 UTC (rev 124922)
+++ mongopersist/trunk/src/mongopersist/performance.py	2012-04-03 18:22:47 UTC (rev 124923)
@@ -12,6 +12,7 @@
 #
 ##############################################################################
 """Mongo Persistence Performance Test"""
+from __future__ import absolute_import
 import optparse
 import persistent
 import pymongo
@@ -72,25 +73,26 @@
     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 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 (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 fast read
     transaction.begin()
     t1 = time.time()
@@ -98,21 +100,42 @@
     #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
         t1 = time.time()

Modified: mongopersist/trunk/src/mongopersist/serialize.py
===================================================================
--- mongopersist/trunk/src/mongopersist/serialize.py	2012-04-03 18:20:33 UTC (rev 124922)
+++ mongopersist/trunk/src/mongopersist/serialize.py	2012-04-03 18:22:47 UTC (rev 124923)
@@ -43,6 +43,26 @@
 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
 
@@ -513,13 +533,14 @@
         # 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



More information about the checkins mailing list