Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it REALLY true that Python code runs faster in a function?

I saw a comment that lead me to the question Why does Python code run faster in a function?.

I got to thinking, and figured I would try it myself using the timeit library, however I got very different results:

(note: 10**8 was changed to 10**7 to make things a little bit speedier to time)

>>> from timeit import repeat
>>> setup = """
def main():
    for i in xrange(10**7):
        pass
"""
>>> stmt = """
for i in xrange(10**7):
    pass
"""
>>> min(repeat('main()', setup, repeat=7, number=10))
1.4399558753975725
>>> min(repeat(stmt, repeat=7, number=10))
1.4410973942722194
>>> 1.4410973942722194 / 1.4399558753975725
1.000792745732109
  • Did I use timeit correctly?
  • Why are these results less 0.1% different from each other, while the results from the other question were nearly 250% different?
  • Does it only make a difference when using CPython compiled versions of Python (like Cython)?
  • Ultimately: is Python code really faster in a function, or does it just depend on how you time it?
like image 798
Wesley Baugh Avatar asked Mar 08 '13 05:03

Wesley Baugh


2 Answers

The flaw in your test is the way timeit compiles the code of your stmt. It's actually compiled within the following template:

template = """
def inner(_it, _timer):
    %(setup)s
    _t0 = _timer()
    for _i in _it:
        %(stmt)s
    _t1 = _timer()
    return _t1 - _t0
"""

Thus stmt is actually running in a function, using the fastlocals array (i.e. STORE_FAST).

Here's a test with your function in the question as f_opt versus the unoptimized compiled stmt executed in the function f_no_opt:

>>> code = compile(stmt, '<string>', 'exec')
>>> f_no_opt = types.FunctionType(code, globals())

>>> t_no_opt = min(timeit.repeat(f_no_opt, repeat=10, number=10))
>>> t_opt = min(timeit.repeat(f_opt, repeat=10, number=10))
>>> t_opt / t_no_opt
0.4931101445632647
like image 84
Eryk Sun Avatar answered Oct 02 '22 22:10

Eryk Sun


It comes down to compiler optimization algorithms. When performing Just-in-time compilation, it is much easier to identify frequently used chunks of code if they're found in functions.

The efficiency gains really would depend on the nature of the tasks being performed. In the example you gave, you aren't really doing anything computationally intensive, leaving fewer opportunities to achieve gains in efficiency through optimization.

As others have pointed out, however, CPython does not do just-in-time compilation. When code is compiled, however, C compilers will often execute them faster.

Check out this document on the GCC compiler: http://gcc.gnu.org/onlinedocs/gcc/Inline.html

like image 33
Ashwin Balamohan Avatar answered Oct 02 '22 22:10

Ashwin Balamohan