Hi Robert,
On 28 Jan., 11:14, Robert Bradshaw <[email protected]>
wrote:
> Yep. It's sad when sometimes it's quicker to not cache non-trivial
> computations.
Indeed it was. Here is an example from the ticket:
Setting:
sage: class A:
....: @cached_method
....: def bar(self,x):
....: return x
....: @cached_in_parent_method
....: def barP(self,x):
....: return x
....: def parent(self):
....: return self
....:
sage: a = A()
WITHOUT #8611, we get:
# The non-critical path:
sage: time for x in range(10^6): b=a.bar(x)
CPU times: user 24.97 s, sys: 0.16 s, total: 25.13 s
Wall time: 25.13 s
sage: time for x in range(10^6): b=a.barP(x)
CPU times: user 41.03 s, sys: 0.13 s, total: 41.16 s
Wall time: 41.17 s
# The critical path (now the values are cached):
sage: time for x in range(10^6): b=a.bar(x)
CPU times: user 16.45 s, sys: 0.02 s, total: 16.47 s
Wall time: 16.47 s
sage: time for x in range(10^6): b=a.barP(x)
CPU times: user 20.47 s, sys: 0.02 s, total: 20.50 s
Wall time: 20.50 s
#########################
WITH #8611, we get:
# The non-critical path:
sage: time for x in range(10^6): b=a.bar(x)
CPU times: user 11.40 s, sys: 0.08 s, total: 11.48 s
Wall time: 11.48 s
sage: time for x in range(10^6): b=a.barP(x)
CPU times: user 27.89 s, sys: 0.12 s, total: 28.01 s
Wall time: 28.02 s
# The critical path (now the values are cached):
sage: time for x in range(10^6): b=a.bar(x)
CPU times: user 3.09 s, sys: 0.01 s, total: 3.10 s
Wall time: 3.10 s
sage: time for x in range(10^6): b=a.barP(x)
CPU times: user 5.25 s, sys: 0.02 s, total: 5.26 s
Wall time: 5.26 s
Hence, due to the optimisation of accessing the cache, it is now
quicker to compute the values *and* store them in the cache (the non-
critical path) than it used to be to only get the cached values that
have been computed before (the critical path).
> +1 to all of the above, I think a cached result should be put on the
> object itself itself.
It still is. In addition, a cached method now *also* belongs to the
object itself.
> > - objects that need fast caching could have x._cache (or maybe even
> > x._cache.foo) as a Cython attribute
>
> That's a really nice idea.
... if the other problems with cached_method+Cython can be solved.
> 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.
There is something called sage.misc.cachefunc.ClearCacheOnPickle. It
is not documented, and I wasn't able to make it work in an example.
But I think the idea is nice: You have one decorator for methods whose
cache should be pickled, and another one where this should not be the
case.
But now that I think about it: It should be easy on top of #8611.
Namely, I.groebner_basis.cache is pickled because I.__dict__ is
pickled and contains I._cache__groebner_basis. Hence, if one modifies
the decorator a little, it should be possible to have the cache in
x.bar.cache, but NOT in x.__dict__['_cache__bar']. In that way, the
cache would not be pickled.
Syntax suggestion:
class FOO:
@cached_method
def bar(self,...):
...
@cached_method(clear=True)
def foo_bar(self,...):
...
Then, when pickling an instance X of FOO, the cache of X.bar would be
pickled, but not the cache of X.foo_bar.
Best regards,
Simon
--
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