Python代码在函数中运行得更快,这真的是真的吗?

时间:2013-03-08 05:42:52

标签: python performance profiling benchmarking cpython

我看到一条评论引导我提出问题Why does Python code run faster in a function?

我开始思考,并想我会使用timeit库自己尝试一下,但是我得到了非常不同的结果:

注意10**8已更改为10**7,以便让时间更快一些)

>>> 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
  • 我是否正确使用timeit
  • 为什么这些结果相差不到0.1%,而另一个问题的结果差异接近250%?
  • 使用 CPython 编译的Python版本(如Cython)时,它只会有所不同吗?
  • 最终:函数中的Python代码真的更快,还是仅仅取决于你如何计时?

2 个答案:

答案 0 :(得分:10)

您的测试中的缺陷是timeit编译stmt代码的方式。它实际上是在以下模板中编译的:

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

因此stmt实际上是在函数中运行,使用fastlocals数组(即STORE_FAST)。

以下是您在f_opt问题中使用函数的函数与函数stmt中执行的未优化编译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

答案 1 :(得分:1)

归结为编译器优化算法。在执行即时编译时,如果在函数中找到它们,则更容易识别经常使用的代码块。

效率提升实际上取决于正在执行的任务的性质。在您给出的示例中,您并没有真正做任何计算密集型工作,从而减少了通过优化实现效率提升的机会。

然而,正如其他人指出的那样,CPython并不进行即时编译。但是,编译代码时,C编译器通常会更快地执行它们。

在GCC编译器上查看此文档:http://gcc.gnu.org/onlinedocs/gcc/Inline.html