As attachement, here's the patch (against rev 2132). It's local to
sqlalchemy/orm/, so:
cd /sqlalchemy/orm
patch -p0 attribute_cache.patch
About the patch itself:
1. the cache should be a WeakKeyDictionary
OK, done. Performances are still OK, differences between built-in dict are
negligible.
2. the cache needs to be cleared for a particular cache (class ?)
If I understand right, while calling register_attribute(), the cache will be
cleared for the given class, if this one has been cached. Is there anywhere
else the cache needs to cleared ?
3. the cache should *probably* be at the module level, and not within
the AttributeManager itself; SA uses only a single AttributeManager per
application so it probably doesnt matter
I let the cache within the AttributeManager... Things can be moved at the
module level, but if it's not necessary right now, it might not be a good
idea to do it right now (when it will be necessary, the design may have been
changed and modifications not valid anymore).
4. the raise should use an exception class of some kind
I've made it raise a TypeError... Yes, string based exceptions are very a bad
thing !
Attributes are cached while using the managed_attributes() *and*
noninherited_managed_attributes() funcs. Those are very similar. I hesitated
refactor them, but centralize cache management is probably a good thing. This
is the purpose of the second patch, which include this refactoring. As
expected, performances decrease. Here's the traditionnal benchmark results:
SA 0.3.1, rev 2127:
total time 4.29376721382
real0m5.420s
user0m4.088s
sys 0m0.108s
SA with attr. cache, no refactoring (~2X faster, back closed to 0.2.8
speed):
total time 2.34819602966
real0m3.013s
user0m2.344s
sys 0m0.088s
SA with attr. cache, with refactoring (30% slower than without
refactoring)
total time 3.05679416656
real0m3.747s
user0m2.988s
sys 0m0.068s
It's up to you choosing the patch ! IMO, I'm *not* in favor to use refactoring
in this case :).
Finally, I've put a clear_attribute_cache func which, ... clear the attribute
cache. While client code may not have to worry about caching, it may need to
clear it...
thanks much, this is the kind of user involvement i like.
Well, you're very welcome ! Glad to help !
Cheers,
Seb
--
Sébastien LELONG
sebastien.lelong[at]sirloon.net
P.S:
im beginning
to suspect that yield introduces overhead vs. a straight list ?
(python interpreter storing stack frames ? dunno).
dunnotoo :)
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups
sqlalchemy group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en
-~--~~~~--~~--~--~---
Index: attributes.py
===
--- attributes.py (révision 2132)
+++ attributes.py (copie de travail)
@@ -609,8 +609,18 @@
class AttributeManager(object):
allows the instrumentation of object attributes. AttributeManager is stateless, but can be
-overridden by subclasses to redefine some of its factory operations.
+overridden by subclasses to redefine some of its factory operations. Also be aware AttributeManager
+will cache attributes for a given class, allowing not to determine those for each objects (used
+in managed_attributes() and noninherited_managed_attributes()). This cache is cleared for a given class
+while calling register_attribute(), and can be cleared using clear_attribute_cache()
+def __init__(self):
+# will cache attributes, indexed by class objects
+self._attribute_cache = weakref.WeakKeyDictionary()
+
+def clear_attribute_cache(self):
+self._attribute_cache.clear()
+
def rollback(self, *obj):
retrieves the committed history for each object in the given list, and rolls back the attributes
each instance to their original value.
@@ -639,21 +649,31 @@
def managed_attributes(self, class_):
returns an iterator of all InstrumentedAttribute objects associated with the given class.
+if self._attribute_cache.has_key(class_):
+return self._attribute_cache[class_]
+
+self._attribute_cache[class_] = []
if not isinstance(class_, type):
-raise repr(class_) + is not a type
+raise TypeError(repr(class_) + is not a type)
for key in dir(class_):
value = getattr(class_, key, None)
if