Sorry for my late answer; I missed this e-mail in the sage-devel flow ...
On Fri, Jan 07, 2011 at 10:58:49AM -0800, Simon King wrote:
> IMHO, the cached_... decorators are currently too slow. It seems to
> me that too much time is spent for looking up the cache (calling the
> method get_cache()).
There is a consensus on that :-)
There are several reasons to cache the results in x rather than in the
method foo:
(a) You don't need to calculate the hash of x to retrieve something
from the cache; that can be important for large objects (with a
costly hash function) with methods taking small arguments as
input.
(b) The cache is automatically pickled with the object
(c) It makes it easy to clear / invalidate the cache of a particular object
(d) If the object goes of scope and is wiped from memory, then the
same occurs to its cache (a desirable feature; otherwise you would
probably be using CachedInParent).
The same apply for CachedInParent: if the parent goes out of
scope, then so does the cache. Otherwise you would probably be
using a cached function.
Note that there is also a little technical hurdle:
sage: class bla:
....: @cached_method
....: def f(): pass
sage: x = bla()
sage: x.f.cache = 1
sage: x.f.cache
------------------------------------------------------------
Traceback (most recent call last):
File "<ipython console>", line 1, in <module>
AttributeError: 'CachedMethodCaller' object has no attribute 'cache'
That's because x.f is a new object each time; the following works:
sage: xf = x.f
sage: xf.cache = 1
sage: xf.cache
1
Of course, that could be worked around by taking over the management
of assignment to x.f.cache using, e.g., a property.
A further note about (c): in fact, I would really like to have all the
cache be grouped in a single attribute x._cache, using x._cache["foo"]
or even x._cache.foo rather than x._cache_foo. Advantages:
- it's easier to clear/invalidate all the cache at once
- less pollution of the name space
- objects that need fast caching could have x._cache (or maybe even
x._cache.foo) as a Cython attribute
There is one issue that needs to be discussed as well: if we change
the location where the cache is stored in objects, then any currently
pickled object will loose its cache. Do we care? I doubt anyone in the
Sage-Combinat crowd cares at this point (we don't have large pickle
jars of objects, especially with relevant cache). But someone else could!
Cheers,
Nicolas
--
Nicolas M. Thi�ry "Isil" <nth...@users.sf.net>
http://Nicolas.Thiery.name/
Yep. It's sad when sometimes it's quicker to not cache non-trivial
computations.
+1 to all of the above, I think a cached result should be put on the
object itself itself.
That's a really nice idea.
> There is one issue that needs to be discussed as well: if we change
> the location where the cache is stored in objects, then any currently
> pickled object will loose its cache. Do we care? I doubt anyone in the
> Sage-Combinat crowd cares at this point (we don't have large pickle
> jars of objects, especially with relevant cache). But someone else could!
I think caches are, by nature, potentially ephemeral, so it's OK to
get back fully-intact objects without their caches. Of coures, someone
may be counting on the fact that they've computed this before
pickling--if so they should speak up now.
- Robert
Oh wow, I had completely missed all the activity on #8611!
This issue had been such an itch since at least one year if not
two. Congrats for getting this done, and so nicely! Thanks to the
reviewers as well. I can't wait for 4.6.2 now!
You are my hero of the day :-)
Cheers,
Nicolas
PS:
Definitely +1 on caching is_subcategory.
The comments in this thread are now for a later ticket.
Out of curiosity: does #8611 keep backward compatibility for the cache
of old pickles?