Hi Simon!

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 :-)

> I'd like to invest some work in it, but I need some info:
> 
> The cache can be
>  * a dictionary self.cache of the decorated function (this is for
> CachedFunction),
>  * a dictionary-like instance self.cache of class FileCache (this is
> for DiskCachedFunction),
>  * a dictionary that is an attribute of the instance to which the
> cached method is bound (this is for CachedMethod), or
>  * a dictionary that is an attribute of the parent of the instance to
> which the cached method is bound (this is for CachedInParentMethod).
> 
> Sometimes, looking up the cache requires two calls (get_cache() and
> _get_instance_cache()). Moreover, C extension types don't provide a
> __dict__ attribute, which is a problem for CachedMethod and
> CachedInParentMethod.
> 
> The cache in the case of CachedFunction and DiskCachedFunction is, of
> course, easy to find: It is self.cache, where "self" is a
> CachedFunction (or DiskCachedFunction) instance.
> 
> Let us now consider CachedMethod.
> Let x be an instance that has a cached method (or cached in parent
> method) foo. The __get__ method of CachedMethod turns x.foo into an
> instance of CachedMethodCaller, that is specific to x. Now, I wonder
> why the method is not cached in an attribute of the CachedMethodCaller
> instance.
> 
> Or explicitly: What is the advantage of caching x.foo in x._cache__foo
> rather than in x.foo.cache? The disadvantage is that the string
> "_cache__foo" must be created and then x.__dict__["_cache__foo"] must
> be obtained, which costs time.

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" <[email protected]>
http://Nicolas.Thiery.name/

-- 
To post to this group, send an email to [email protected]
To unsubscribe from this group, send an email to 
[email protected]
For more options, visit this group at http://groups.google.com/group/sage-devel
URL: http://www.sagemath.org

Reply via email to