我看到一条评论引导我提出问题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 :(得分: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