On Sep 9, 6:35 pm, Justin Walker <[EMAIL PROTECTED]> wrote:
> Hi, all,
>
> Whilst looking at some code, I noticed that a computation was being  
> repeated on each call, although the inputs to the computation never  
> changed (these were values used to define an instance of a class).  I  
> decided to cache the value and return it rather than recomputing it.  
> To see the effects I ran "%timeit" on the function before and after.
>
> I was surprised to find that the 'cached' version ran some 50 times  
> slower than the direct computation (in my case, 300 microseconds vs. 6  
> microseconds).
>
> I traced the cached version to see what was causing the time  
> increase.  The code is
>     def blah(self):
>         # self.val is initialized to 'None' when the class is  
> instantiated.
>         if self.val == None:
>             self.val = arithmetic_expression
>         return self.val
>
> The first time through, control passes through the computation and  
> returns the value (after storing it).  The second time through, the  
> "traced" execution goes wandering off into the weeds, starting with
>     /SandBox/Justin/sb/sage/local/lib/python2.5/
> traceback.py(232)format_exc()
>
> and ending up in getline() before I get bored and quit.  If I step  
> through this, using "return" all the way, execution just terminates  
> back at the sage prompt, with no output.
>
> I can't tell if this is just an artifact of some funky debugging  
> interaction (am I debugging the debugger?), or whether this is really  
> where the code goes.
>
> Anyone have a clue to spare?  Something I'm missing?
>
> Justin

It looks like the check to see if your expression is none is actually
dominating the run time of this function (see mhansen's response).
First, that suggests that this is a poor candidate for caching.
Premature optimization is the root of all evil, etc.

You can avoid doing the comparison at all by actually replacing the
method after the first time through:

class myClass():

    def blah(self):
         # 'long' computation
        a = n(log(factorial(10)))
        # replace the original method with a
        # function that just returns the answer
        self.blah = lambda : a
        # The rest only gets executed the first
        # time through
        print 'First Time'
        return self.blah()

sage: mc = myClass()
sage: mc.blah()
First Time
15.1044125730755
sage: mc.blah()
15.1044125730755

sage: timeit('n(log(factorial(10)))')
625 loops, best of 3: 120 µs per loop
sage: timeit('mc.blah()')
625 loops, best of 3: 594 ns per loop

There may be a more pythonic way to do this--I'm just trying to
translate something I saw in Ruby.  I think I've seen at least one
person define an @cache decorator somewhere on the web.

Cheers,

JM
--~--~---------~--~----~------------~-------~--~----~
To post to this group, send email to sage-devel@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at http://groups.google.com/group/sage-devel
URLs: http://www.sagemath.org
-~----------~----~----~----~------~----~------~--~---

Reply via email to