[Python-Dev] default of returning None hurts performance?

Steven D'Aprano steve at pearwood.info
Tue Sep 1 15:04:50 CEST 2009


On Tue, 1 Sep 2009 05:51:49 pm Scott Dial wrote:
> Raymond Hettinger wrote:
> >> I was just wondering if a bytecode for a superinstruction of the
> >> common sequence:
> >>
> >> 6 POP_TOP
> >> 7 LOAD_CONST 0 (None)
> >> 10 RETURN_VALUE
> >>
> >> might be worth it.
> >
> > [Collin Winter]
> >
> >> I doubt it. You'd save a bit of stack manipulation, but since this
> >> will only appear at the end of a function, I'd be skeptical that
> >> this would make any macrobenchmarks (statistically) significantly
> >> faster.
> >
> > I concur with Collin.  And since it appears only at the end of a
> > function, the optimization doesn't help inner-loops in a function
> > (where most of the time usually spent).
>
> I fail to understand this crude logic. How often is the inner-loop
> really going to solely call C code? Any call to Python in an
> inner-loop is going to suffer this penalty on the order of the number
> of loop iterations)?

Most functions don't suffer this penalty. Consider the following two 
functions:


def g(x):
    return x()

def h(x):
    x()

Now disassemble:

>>> dis.dis(g)
  2           0 LOAD_FAST                0 (x)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE
>>> dis.dis(h)
  2           0 LOAD_FAST                0 (x)
              3 CALL_FUNCTION            0
              6 POP_TOP
              7 LOAD_CONST               0 (None)
             10 RETURN_VALUE

The first doesn't suffer any such default "return None" penalty, and so 
won't gain any performance benefit from optimizing it. It is only the 
subset of functions which don't explicitly return anything which will 
see any potential benefit. Let me call such functions "procedures" to 
avoid confusion with those functions which won't see any benefit.

While procedures may see some benefit, it's a trivial amount, probably 
not worth the extra complexity. According to Gregory's tests, the 
difference is approximately 2% on a trivial do-nothing function. 
According to my tests on my PC, I might hope to save somewhat less than 
0.1 microsecond per procedure call as an absolute saving. As a relative 
saving though, it will most likely be insignificant: for comparison's 
sake, urllib2.Request('http://example.com') takes around 150μs on my 
machine, and math.sin(1.1) around 90μs. For any procedure which does 
non-trivial amounts of work, saving 0.1μs is insignificant, no matter 
how many times it is called inside a loop.


-- 
Steven D'Aprano


More information about the Python-Dev mailing list