Python中for和while循环之间的性能差异

时间:2020-05-18 10:24:39

标签: python performance for-loop while-loop

Python's documentation表明for语句实际上是语法糖,它掩盖了迭代器和可迭代对象概念的复杂性。如果是这样,则意味着以下两个功能相同:

def for_loop(seq):
    for i in seq:
        i

def while_loop(seq):
    iseq = iter(seq)
    _loop = True
    while _loop:
        try:
            i = next(iseq)
        except StopIteration:
            _loop = False
        else:
            i

请注意,为了使for语句的性能更好,我将循环的主体尽可能地简化,因此避免了调用print(或类似函数)

以下是在IPython中测量这些功能的性能后的结果:

In [43]: %timeit for_loop(range(1000))                                                                                                                                
22.9 µs ± 356 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [44]: %timeit while_loop(range(1000))                                                                                                                              
49.9 µs ± 825 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

In [45]: %timeit for_loop(range(100000))                                                                                                                              
2.63 ms ± 43.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

In [46]: %timeit while_loop(range(100000))                                                                                                                            
5.16 ms ± 69.8 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

for语句实际上是while循环的两倍(在传递长列表而不是长迭代器时,观察到1.6的差异要小一些)。对于len(seq)的值范围,性能差异是恒定的。我还观察到,当我使用dis模块反汇编它们时,这些函数的字节码有所不同。

总结:Python的文档指出,使用for语句时,Python实际上将其作为while_loop的封面运行。有人可以用Pythoneer解决性能差异和特殊性的问题吗?它的根源是什么(CPython优化,...)?

1 个答案:

答案 0 :(得分:1)

一些注意事项:

  • 从功能的角度来看,for实际上只是while的语法加糖,这意味着它实际上具有相同的实现。不同的实现可能具有非常不同的性能。
  • 如果查看cpython实现,您会发现forwhile确实有不同的实现。例如,请参见https://github.com/python/cpython/blob/ee40e4b8563e6e1bc2bfb267da5ffc9a2293318d/Python/compile.c
  • 中的函数compiler_whilecompiler_for
  • 我怀疑for对范围进行了某种优化。当不是用range(1000000)来计时两个功能时,我用np.random.rand(1000000)来计时它们时,间隔从笔记本电脑上的3倍(24毫秒对73毫秒)下降到50%(101毫秒对155毫秒)。